My problem is specific to Go-kit and how to organize code within. I'm trying to write a unit test for the following function:
func MakeHandler(svc Service, logger kitlog.Logger) http.Handler {
orderHandler := kithttptransport.NewServer(
makeOrderEndpoint(svc),
decodeRequest,
encodeResponse,
)
r := mux.NewRouter()
r.Handle("/api/v1/order/", orderHandler).Methods("GET")
return r
}
What would be the correct way of writing a proper unit test? I have seen examples such as the following:
sMock := &ServiceMock{}
h := MakeHandler(sMock, log.NewNopLogger())
r := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/api/v1/order/", bytes.NewBuffer([]byte("{}")))
h.ServeHTTP(r, req)
And then testing the body and headers of the request. But this doesn't seem like a proper unit test, as calls other parts of the code (orderHandler
). Is it possible to just validate what's returned from MakeHandler()
instead of during a request?
TL;DR: Yes, that test is in the right direction. You shouldn't try to test the internals of the returned handler since that third party package may change in ways you didn't expect in the future.
Is it possible to just validate what's returned from MakeHandler() instead of during a request?
Not in a good way. MakeHandler()
returns an interface and ideally you'd use just the interface methods in your tests.
You could look at the docs of the type returned by mux.NewRouter()
to see if there are any fields or methods in the concrete type that can give you the information, but that can turn out to be a pain - both for understanding the tests (one more rarely used type to learn about) and due to how future modifications to the mux
package may affect your code without breaking the tests.
What would be the correct way of writing a proper unit test?
Your example is actually in the right direction. When testing MakeHandler()
, you're testing that the handler returned by it is able to handle all the paths and calls the correct handler for each path. So you need to call the ServeHTTP()
method, let it do its thing and then test to see it worked correctly. Only introspecting the handler does not guarantee correctness during actual usage.
You may need to make actually valid requests though so you're able to understand which handler was called based on the response body or header. That should bring the test to a quite reasonable state. (I think you already have that)
Similarly, I'd add a basic sub test for each route that's added in the future. Detailed handler tests can be written in separate funcs.