Followup question to: 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?
CodePudding user response:
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")
}
}