04/02/2020 - GO
Assume that when you call an endpoint in your application, it calls an external service. If you write a test for it without mocking the external service, your test will actually call the external service. To avoid such issue, you can mock it in your tests as shown below.
This is the one that calls the external service behind the scene but we are not going to write a test for it. Instead we are going to pass the mock server's address to it in our test.
package pkg
import "net/http"
type Consumer struct {
ServiceAddress string
}
func (c Consumer) GetUsers() (*http.Response, error) {
req, err := http.NewRequest(http.MethodGet, c.ServiceAddress + "/server/api/v1/users", nil)
if err != nil {
return nil, err
}
client := http.Client{}
res, err := client.Do(req)
if err != nil {
return nil, err
}
return res, nil
}
package app
import (
"io/ioutil"
"net/http"
"internal/pkg"
)
type User struct {
ServiceConsumer pkg.Consumer
}
func (u User) Create(w http.ResponseWriter, r *http.Request) {
res, err := u.ServiceConsumer.GetUsers()
if err != nil {
_, _ = w.Write([]byte(err.Error()))
return
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
_, _ = w.Write([]byte(err.Error()))
return
}
res.Body.Close()
_, _ = w.Write(body)
}
package app
import (
"net/http"
"net/http/httptest"
"testing"
"internal/pkg"
)
func TestUser_Create(t *testing.T) {
srv := serverMock()
defer srv.Close()
req := httptest.NewRequest(http.MethodGet, "/client/api/v1/users", nil)
res := httptest.NewRecorder()
user := User{ServiceConsumer: pkg.Consumer{ServiceAddress: srv.URL}}
user.Create(res, req)
if http.StatusOK != res.Code {
t.Error("expected", http.StatusOK, "got", res.Code)
}
if "mock server responding" != res.Body.String() {
t.Error("expected mock server responding got", res.Body.String())
}
}
func serverMock() *httptest.Server {
handler := http.NewServeMux()
handler.HandleFunc("/server/api/v1/users", usersMock)
srv := httptest.NewServer(handler)
return srv
}
func usersMock(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte("mock server responding"))
}