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

Go Echo服务端测试时FormParams无法获取表单值求助

问题解决:Echo框架测试中ctx.FormParams()无法获取表单值

核心问题分析

你的CreateNode接口依赖ctx.FormParams()获取数据,这个方法只负责解析表单类型的请求体(application/x-www-form-urlencoded或multipart/form-data),完全不处理JSON格式的请求,所以你用JSON请求的方式从一开始就走不通。

再看你注释掉的表单请求代码,问题出在Content-Type设置错误:你用url.Values.Encode()生成的是application/x-www-form-urlencoded格式的内容,却把请求头设成了multipart/form-data,导致Echo无法正确解析请求体。

正确的测试方案

根据你的接口实际接收的表单类型,选择对应的测试写法:

方案1:接口接收application/x-www-form-urlencoded表单

这是普通表单的标准格式,修改测试代码如下:

func TestCreateNode(t *testing.T) {
    expected := "Node created, hooray\n"

    api := &ServerImplementation{}
    err := api.Init("host=localhost database=pgx_test user=postgres")
    if err != nil {
        t.Fatal(err)
    }
    t.Cleanup(func() {
        t.Log("Cleaning up API")
        api.Close()
    })

    e := echo.New()

    // 构造x-www-form-urlencoded格式的表单数据
    formVals := make(url.Values)
    formVals.Set("name", "node1")
    reqBody := strings.NewReader(formVals.Encode())
    
    // 注意这里的Content-Type要和请求体格式匹配
    req := httptest.NewRequest(echo.POST, "/api/nodes", reqBody)
    req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationFormURLEncoded)
    
    rec := httptest.NewRecorder()
    ctx := e.NewContext(req, rec)

    if assert.NoError(t, api.CreateNode(ctx)) {
        assert.Equal(t, http.StatusOK, rec.Code)
        assert.Equal(t, expected, rec.Body.String())
    }
}

方案2:接口接收multipart/form-data表单

如果你的接口是处理带文件的多部分表单,需要用multipart.Writer构造请求体:

func TestCreateNode(t *testing.T) {
    expected := "Node created, hooray\n"

    api := &ServerImplementation{}
    err := api.Init("host=localhost database=pgx_test user=postgres")
    if err != nil {
        t.Fatal(err)
    }
    t.Cleanup(func() {
        t.Log("Cleaning up API")
        api.Close()
    })

    e := echo.New()

    // 创建multipart writer构造请求体
    var buf bytes.Buffer
    writer := multipart.NewWriter(&buf)
    // 添加表单字段
    field, err := writer.CreateFormField("name")
    if err != nil {
        t.Fatal(err)
    }
    _, _ = field.Write([]byte("node1"))
    // 如果有文件可以用CreateFormFile
    // fileField, err := writer.CreateFormFile("file", "test.txt")
    // ...
    writer.Close()

    req := httptest.NewRequest(echo.POST, "/api/nodes", &buf)
    // 这里要用writer.FormDataContentType()获取正确的Content-Type(包含boundary)
    req.Header.Set(echo.HeaderContentType, writer.FormDataContentType())
    
    rec := httptest.NewRecorder()
    ctx := e.NewContext(req, rec)

    if assert.NoError(t, api.CreateNode(ctx)) {
        assert.Equal(t, http.StatusOK, rec.Code)
        assert.Equal(t, expected, rec.Body.String())
    }
}

额外说明

关于测试路径:你的实际端点是/api/nodes,测试里之前用/虽然直接调用方法不会影响路由匹配,但建议保持路径一致,避免后续测试出现其他问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 15:11:23