英文:
How to assert that the request happened when mocking an API concurrently?
问题
对于您提供的代码和问题,我将为您进行翻译:
package main
import (
"net/http"
)
func SomeFeature(host, a string) {
if a == "foo" {
resp, err := http.Get(host + "/foo")
}
if a == "bar" {
resp, err := http.Get(host + "/baz"))
}
// baz is missing, the test should error!
}
package main
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestSomeFeature(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
}))
testCases := []struct {
name string
variable string
}{
{
name: "test 1",
variable: "foo",
},
{
name: "test 2",
variable: "bar",
},
{
name: "test 3",
variable: "baz",
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
SomeFeature(server.URL, tc.variable)
// assert that the http call happened somehow?
})
}
}
- GO Playground: https://go.dev/play/p/EFanSSzgnbk
- 如何断言每个测试用例都发送了请求到模拟服务器?
- 如何断言请求未发送?
同时保持测试并行/并发进行?
希望对您有所帮助!
英文:
Followup question to: https://stackoverflow.com/questions/70087909/how-do-i-guarantee-that-the-request-happened-correctly-when-mocking-an-api
main.go
package main
import (
"net/http"
)
func SomeFeature(host, a string) {
if a == "foo" {
resp, err := http.Get(host + "/foo")
}
if a == "bar" {
resp, err := http.Get(host + "/baz"))
}
// baz is missing, the test should error!
}
main_test.go
package main
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestSomeFeature(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
}))
testCases := []struct {
name string
variable string
}{
{
name: "test 1",
variable: "foo",
},
{
name: "test 2",
variable: "bar",
},
{
name: "test 3",
variable: "baz",
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
SomeFeature(server.URL, tc.variable)
// assert that the http call happened somehow?
})
}
}
- GO Playground: https://go.dev/play/p/EFanSSzgnbk
- How to do I assert that each test case send a request to the mocked server?
- How can I assert that a request wasn't sent?
All while keeping the tests parallel/concurrent?
答案1
得分: 3
你可以为每个测试用例创建一个新的服务器。
或者你可以使用通道,具体来说是一个通道映射,其中键是测试用例的标识符,例如:
getChans := map[string]chan struct{}{}
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
key := strings.Split(r.URL.Path, "/")[1] // 从路径中提取通道键
go func() { getChans[key] <- struct{}{} }()
w.WriteHeader(200)
}))
在测试用例中添加一个通道键字段。这将添加到主机的URL中,处理程序将提取键,如上所示,以获取正确的通道。还添加一个字段来指示是否应调用http.Get
:
testCases := []struct {
name string
chkey string
variable string
shouldGet bool
}{
{
name: "test 1",
chkey: "key1",
variable: "foo",
shouldGet: true,
},
// ...
}
在运行测试用例之前,将测试用例特定的通道添加到映射中:
getChans[tc.chkey] = make(chan struct{})
然后在测试用例中使用通道键字段作为主机URL路径的一部分:
err := SomeFeature(server.URL+"/"+tc.chkey, tc.variable)
if err != nil {
t.Error("SomeFeature should not error")
}
要检查是否调用了http.Get
,请使用select
和一些可接受的超时时间:
select {
case <-getChans[tc.chkey]:
if !tc.shouldGet {
t.Error(tc.name + " get called")
}
case <-time.Tick(3 * time.Second):
if tc.shouldGet {
t.Error(tc.name + " get not called")
}
}
https://go.dev/play/p/7By3ArkbI_o
英文:
You could create a new server for each test case.
Or you can use channels, specifically a map of channels where the key is the test case's identifier, e.g.
getChans := map[string]chan struct{}{}
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
key := strings.Split(r.URL.Path, "/")[1] // extract channel key from path
go func() { getChans[key] <- struct{}{} }()
w.WriteHeader(200)
}))
Add a channel key field to the test case. This will be added to the host's URL and the handler will then extract the key, as demonstrated above, to get the correct channel. Also add a field to indicate whether http.Get
should be called or not:
testCases := []struct {
name string
chkey string
variable string
shouldGet bool
}{
{
name: "test 1",
chkey: "key1"
variable: "foo",
shouldGet: true,
},
// ...
}
Before running the test case add the test-case-specific channel to the map:
getChans[tc.chkey] = make(chan struct{})
Then use the channel key field in the test case as part of the host's URL path:
err := SomeFeature(server.URL+"/"+tc.chkey, tc.variable)
if err != nil {
t.Error("SomeFeature should not error")
}
And to check whether or not http.Get
was called use select
with some acceptable timeout:
select {
case <-getChans[tc.chkey]:
if !tc.shouldGet {
t.Error(tc.name + " get called")
}
case <-time.Tick(3 * time.Second):
if tc.shouldGet {
t.Error(tc.name + " get not called")
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论