You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go Fiber创建用户单元测试500错误及类型转换问题修复

创建用户单元测试500错误及nil转换panic解决

问题描述

为创建用户功能编写单元测试时,测试始终返回500 Internal Server Error,实际运行main.go时该功能正常。测试过程中触发interface conversion: interface {} is nil, not map[string]interface {} panic。

相关代码

测试代码(package test)

func setupDB() *sql.DB {

    var (   
        username = "root"
        password = "root"
        host = "localhost"
        port = "3306"
        db_name = "go-fiber-test"
    )

    dns := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=True", username, password, host, port, db_name)

    db, err := sql.Open("mysql", dns)
    if err != nil {
        panic(err)
    }

    db.SetMaxIdleConns(10)
    db.SetMaxOpenConns(100)
    db.SetConnMaxIdleTime(5 * time.Minute)
    db.SetConnMaxLifetime(60 * time.Minute)

    return db
}

func setupRouter(db *sql.DB) *fiber.App{

    validator := validator.New()
    userRepository := repository.NewUserRepository()
    userService := service.NewUserService(userRepository, db, validator)
    userController := controller.NewUserController(userService)
    
    router := route.RouteInit(userController)

    return router
}


func truncateUsers(db *sql.DB)  {
    db.Exec("TRUNCATE users")
}

func TestCreateUsersSuccess(t *testing.T) {
    db := setupDB()
    router := setupRouter(db)

    requestBody := strings.NewReader(`
        {
            "name": "myname",
            "email": "mynamecool329@gmail.com",
            "password": "myname!@#",
            "address": "Jl. nanananaaana",
            "phone": "0812388773342"
        }
    `)

    request := httptest.NewRequest("POST", "http://localhost:3000/users/create", requestBody)
    
    response, err := router.Test(request)
    helper.PanicIfError(err)

    assert.Equal(t, 200, response.StatusCode)

    body, err := io.ReadAll(response.Body)
    helper.PanicIfError(err)
    var responseBody map[string]interface{}
    err = json.Unmarshal(body, &responseBody)
    helper.PanicIfError(err)

    log.Printf("request          : %v", request)
    log.Printf("response         : %v", response)
    log.Printf("response body    : %v", response.Body)
    log.Printf("response body Map: %v", responseBody)

    assert.Equal(t, 200, int(responseBody["code"].(float64)))
    assert.Equal(t, "SUCCESS", responseBody["status"])
    assert.Equal(t, "myname", responseBody["data"].(map[string]interface{})["name"])
}

路由代码(package route)

func RouteInit(userController controller.UserController) *fiber.App {

    app := fiber.New()

    app.Use(func(c *fiber.Ctx) error {
        defer func() {
            if err := recover(); err != nil {
                exception.ErrorHandler(c, err)
            }
        }()
    
        return c.Next()
    })

    app.Get("/users", middleware.AuthMiddleware, userController.FindAll)
    app.Get("/users/:userId", userController.FindById)
    app.Put("/users/:userId", middleware.AuthMiddleware, userController.Update)
    app.Delete("/users/:userId", middleware.AuthMiddleware, userController.Delete)
    app.Post("/users/create", userController.Create)

    app.Post("/login", userController.Login)
    app.Get("/logout", middleware.AuthMiddleware, userController.Logout)
    app.Post("/verify", userController.Verify)

    return app
}

错误输出

=== RUN   TestCreateUsersSuccess
2023/02/16 11:22:00 request          : &{POST http://localhost:3000/users/create HTTP/1.1 1 1 map[Content-Length:[163]] {
                {
                        "name": "myname",
                        "email": "mynamecool329@gmail.com",
                        "password": "myname!@#",
                        "address": "Jl. nanananaaana",
                        "phone": "0812388773342"
                }
        } <nil> 163 [] false localhost:3000 map[] map[] <nil> map[] 192.0.2.1:1234 http://localhost:3000/users/create <nil> <nil> <nil> <nil>}
2023/02/16 11:22:00 response         : &{200 OK 200 HTTP/1.1 1 1 map[Content-Length:[57] Content-Type:[application/json] Date:[Thu, 16 Feb 2023 04:22:00 GMT]] 0xc00037b940 57 [] false false map[] 0xc000113d00 <nil>}
2023/02/16 11:22:00 response body    : &{0xc00000edb0 <nil> <nil> false false {0 0} true false false <nil>}
2023/02/16 11:22:00 response body Map: map[code:500 data:<nil> status:INTERNAL SERVER ERROR]
    /home/myname/Documents/Go/go-fiber/unit-test/user/create_test.go:99:
                Error Trace:    /home/myname/Documents/Go/go-fiber/unit-test/user/create_test.go:99
                Error:          Not equal:
                                expected: 200
                                actual  : 500
                Test:           TestCreateUsersSuccess
    /home/myname/Documents/Go/go-fiber/unit-test/user/create_test.go:100:
                Error Trace:    /home/myname/Documents/Go/go-fiber/unit-test/user/create_test.go:100
                Error:          Not equal:
                                expected: "SUCCESS"
                                actual  : "INTERNAL SERVER ERROR"

                                Diff:
                                --- Expected
                                +++ Actual
                                @@ -1 +1 @@
                                -SUCCESS
                                +INTERNAL SERVER ERROR
                Test:           TestCreateUsersSuccess
--- FAIL: TestCreateUsersSuccess (0.00s)
panic: interface conversion: interface {} is nil, not map[string]interface {} [recovered]
        panic: interface conversion: interface {} is nil, not map[string]interface {}

goroutine 6 [running]:
testing.tRunner.func1.2({0x7e5700, 0xc0003c13b0})
        /usr/lib/go-1.18/src/testing/testing.go:1389 +0x24e
testing.tRunner.func1()
        /usr/lib/go-1.18/src/testing/testing.go:1392 +0x39f
panic({0x7e5700, 0xc0003c13b0})
        /usr/lib/go-1.18/src/runtime/panic.go:838 +0x207
go_fiber/unit-test/user.TestCreateUsersSuccess(0x0?)
        /home/myname/Documents/Go/go-fiber/unit-test/user/create_test.go:101 +0x425
testing.tRunner(0xc00037c9c0, 0x87f6b8)
        /usr/lib/go-1.18/src/testing/testing.go:1439 +0x102
created by testing.(*T).Run
        /usr/lib/go-1.18/src/testing/testing.go:1486 +0x35f
FAIL    go_fiber/unit-test/user 0.027s

解决方案

1. 补全请求Content-Type头

Fiber需要明确的Content-Type头才能解析JSON请求体,在测试代码中添加该头:

request := httptest.NewRequest("POST", "http://localhost:3000/users/create", requestBody)
request.Header.Set("Content-Type", "application/json") // 新增此行

2. 避免nil类型转换panic

当返回500错误时,responseBody["data"]为nil,直接转换会触发panic。修改断言逻辑:

// 替换原有的assert.Equal(t, "myname", responseBody["data"].(map[string]interface{})["name"])
if data, ok := responseBody["data"].(map[string]interface{}); ok && data != nil {
    assert.Equal(t, "myname", data["name"])
} else {
    t.Fatal("响应数据为nil或非预期格式")
}

3. 验证数据库连接

在setupDB中添加Ping操作,确保数据库连接有效:

db, err := sql.Open("mysql", dns)
if err != nil {
    panic(err)
}
// 新增Ping验证
if err := db.Ping(); err != nil {
    panic(err)
}

4. 处理截断表操作的错误并清理数据

完善truncateUsers函数的错误处理,并在测试结束后自动清理数据:

func truncateUsers(db *sql.DB) {
    _, err := db.Exec("TRUNCATE users")
    helper.PanicIfError(err) // 新增错误处理
}

func TestCreateUsersSuccess(t *testing.T) {
    db := setupDB()
    defer truncateUsers(db) // 延迟调用,测试结束后清空表
    router := setupRouter(db)
    // ... 后续代码
}

内容的提问来源于stack exchange,提问作者leo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 00:05:20