I have a simple service created using infinite loop to call a certain HTTP API periodically, implemented in a package aservice
. I created a Service
struct there. Typically, to run that service, I expose a StartService
method which is used to run that service synchronously. Users of the package can then run it using a goroutine. My question is, how do you write the tests for this kind of scenario?
Do you run the whole system and "mock" the API? I have heard that code that uses 3rd party services don't need to be tested, but the whole aservice
package may only contain StartService
and Shutdown
methods. The rest of them are unexported functions/methods which are then cannot be tested individually. If that is the case then I can't write any tests at all?
With Go you will have awesome experience while mocking external http requests. Long story short just substitute base url with server url from net/http/httptest package. You can mimic the way Google mocks their external requests for example exploring tests in google maps here.
server := mockServer(200, response)
defer server.Close()
c, _ := NewClient(WithAPIKey(apiKey), WithBaseURL(server.URL))
r := &DirectionsRequest{
Origin: "Google Sydney",
Destination: "Glebe Pt Rd, Glebe",
Mode: TravelModeTransit,
}
resp, _, err := c.Directions(context.Background(), r)
// your assertions goes here
// Create a mock HTTP Server that will return a response with HTTP code and body.
func mockServer(code int, body string) *httptest.Server {
server := mockServerForQuery("", code, body)
return server.s
}
func mockServerForQuery(query string, code int, body string) *countingServer {
server := &countingServer{}
server.s = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if query != "" && r.URL.RawQuery != query {
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(query, r.URL.RawQuery, false)
log.Printf("Query != Expected Query: %s", dmp.DiffPrettyText(diffs))
server.failed = append(server.failed, r.URL.RawQuery)
http.Error(w, "fail", 999)
return
}
server.successful++
w.WriteHeader(code)
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
fmt.Fprintln(w, body)
}))
return server
}