Go 测试失败 db 查询(零指针)但适用于 Postman/Curl

Posted

技术标签:

【中文标题】Go 测试失败 db 查询(零指针)但适用于 Postman/Curl【英文标题】:Go test fails db query (nil pointer) but works with Postman/Curl 【发布时间】:2022-01-03 09:42:17 【问题描述】:

我正在测试 GetCats(),这是一个从 mysql 数据库中获取所有“猫”的函数。当我通过邮递员到达端点时,由于 'COALESCE' 将字段设置为空字符串(如果为 null),因此不会出现 nil 指针错误。

但是,当我测试该函数时,出现了一个 nil 指针错误并且程序崩溃了。

panic: runtime error: invalid memory address or nil pointer dereference [recovered]

_test.go

func TestGetCats(t *testing.T) 
    // create new request to /cats endpoint, nil => body io.Reader
    req, err := http.NewRequest("GET", "/cats", nil)
    if err != nil 
        t.Fatal(err)
    
    // Will store response received from /cats endpoint => pointer to ResonseRecorder struct
    recorder := httptest.NewRecorder()

    handler := http.HandlerFunc(handlers.GetCats)

    // ----(FAILS HERE) hit endpoint with recorder and request (FAILS HERE) ----//
    handler.ServeHTTP(recorder, req)

    // ------------------------------------------------------------------------//

    // test recorder status code
    if recorder.Code != http.StatusOK 
        t.Errorf("getCats return wrong status code: got %v but want %v", recorder.Code, http.StatusOK)
    

cathandlers.go

func GetCats(w http.ResponseWriter, r *http.Request) 
    w.Header().Set("Content-Type", "application/json")

    var animals []Animal

    // ---------------Program panics on this query --------------------//
    // cannot input null values into struct => return empty string instead
    
    res, err := Db.Query("SELECT id, name, 
                            COALESCE(age, '') as age, 
                            COALESCE(color, '') as color,
                            COALESCE(gender, '') as gender, 
                            COALESCE(breed, '') as breed, 
                            COALESCE(weight, '') as weight FROM cats")

    //------------------------------------------------//

任何帮助将不胜感激!

补充说明:

'name' 在数据库中不为空,不需要在该字段上合并 数据库中有几个空字段(故意) 只是对查询在邮递员中的工作方式感到困惑,但在从 _test.go 内部调用时却没有

【问题讨论】:

我的猜测是,这与查询本身没有太大关系,而是与 Db 的初始化方式有关。也许它是由您的 main() 函数初始化的,在运行测试时不会执行。 谢谢@mkopriva,这正是问题所在 【参考方案1】:

可能 Db 对象在测试中未正确初始化。您最好定义一个结构并将数据库注入为依赖项,并在测试中使用假数据库对象。例如,

// handlers.go
import (
        "database/sql"
        "net/http"
)

type App struct 
        DB *sql.DB


func (a *App) GetCats(w http.ResponseWriter, r *http.Request) 
        // var animals []Animal

        res, err := a.DB.Query("SELECT id, name, 
                            COALESCE(age, '') as age, 
                            COALESCE(color, '') as color,
                            COALESCE(gender, '') as gender, 
                            COALESCE(breed, '') as breed, 
                            COALESCE(weight, '') as weight FROM cats")

      // ....


// handlers_test.go
import (
        "net/http"
        "net/http/httptest"
        "testing"

        "github.com/DATA-DOG/go-sqlmock"
)

func TestGetCats(t *testing.T) 
        db, _, err := sqlmock.New()
        if err != nil 
                t.Fatalf("an error %s was not expected when openning a stub database connection", err)
        

        app := &App
                DB: db,
        

        req, err := http.NewRequest("GET", "/cats", nil)
        if err != nil 
                t.Fatal(err)
        
        // Will store response received from /cats endpoint => pointer to ResonseRecorder struct
        recorder := httptest.NewRecorder()

        // DB expected actions...

        handler := http.HandlerFunc(app.GetCats)
        handler.ServeHTTP(recorder, req)

        if recorder.Code != http.StatusOK 
                t.Errorf("getCats return wrong status code: got %v but want %v", recorder.Code, http.StatusOK)
        


【讨论】:

感谢@Phuc,这真的很有帮助!

以上是关于Go 测试失败 db 查询(零指针)但适用于 Postman/Curl的主要内容,如果未能解决你的问题,请参考以下文章

灵活查询适用于 HANA DB,但不适用于 HSQL DB

为啥 django test --keep-db 适用于 postgres 数据库但不适用于默认 sqlite3

Django 测试因 InternalError 失败:没有这样的保存点。 DB:Postgres,通过 mysql

angularJS ajax 调用失败 403 但 jQuery ajax 调用适用于跨站点 templateUrl 加载。 [复制]

Go mod 下载得很好,但 golint 在假定下载的依赖项上失败了

golang GoLang数据库SQL:从查询中选择未知数量的列。基准测试结果为db_test.go