Go并发测试中模拟API时如何断言请求是否已发起
解决方案
因为需要保留测试并行执行的特性,必须避免多个子测试共享同一个模拟服务端导致的请求统计混淆,最优方案是每个并行子测试独立创建专属的httptest服务端,单独统计当前测试触发的请求。
实现逻辑
- 移除所有子测试共用的公共httptest服务端,改为每个
t.Run内部启动专属服务端,每个服务端的Handler仅记录当前测试触发的请求 - 用切片记录当前服务端收到的所有请求路径、请求方法等信息,因为是当前子测试独有的变量,不存在并发冲突
- 断言请求已发送:测试执行完成后检查预期路径存在于记录的切片中
- 断言请求未发送:测试执行完成后检查目标路径不存在于记录的切片中
修正后的测试代码
package main import ( "net/http" "net/http/httptest" "testing" ) func TestSomeFeature(t *testing.T) { testCases := []struct { name string variable string expectPath string shouldSend bool }{ { name: "test 1", variable: "foo", expectPath: "/foo", shouldSend: true, }, { name: "test 2", variable: "bar", expectPath: "/baz", shouldSend: true, }, { name: "test 3", variable: "baz", expectPath: "/baz", shouldSend: true, // 原逻辑缺失baz分支,该测试会按预期报错 }, { name: "test 4: 断言请求未发送示例", variable: "unknown", expectPath: "/any", shouldSend: false, }, } for _, tc := range testCases { tc := tc t.Run(tc.name, func(t *testing.T) { t.Parallel() // 每个子测试单独创建专属测试服务端 var receivedPaths []string server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { receivedPaths = append(receivedPaths, r.URL.Path) w.WriteHeader(http.StatusOK) })) defer server.Close() // 执行待测逻辑 SomeFeature(server.URL, tc.variable) // 执行断言 pathExists := false for _, p := range receivedPaths { if p == tc.expectPath { pathExists = true break } } if tc.shouldSend && !pathExists { t.Errorf("预期请求路径 %s 未被发送", tc.expectPath) } if !tc.shouldSend && pathExists { t.Errorf("预期不被发送的请求路径 %s 实际已发送", tc.expectPath) } }) } }
额外说明
原main.go代码中a == "bar"分支的http.Get调用存在语法错误,多了一个冗余右括号,需要先修正为resp, err := http.Get(host + "/baz")才能正常编译运行。
内容的提问来源于stack exchange,提问作者Timo Huovinen
相关产品推荐
相关产品推荐

