Use dependency injection. Dependency injection is a design pattern that decouples dependencies between two or more layers of software.
How it works
Pass a dependency to the Login function. In Go, the dependency is often an interface type. Interfaces express generalizations or abstractions about the behaviors of other types. A type satisfies an interface if it has all the methods in the interface. With an interface, you can replace a real object with a fake one (a mock) in your tests. This works without Go's type system complaining as long as a concrete type satisfies the interface.
type Auther interface {
Login(cred *serializers.LoginReq) (*serializers.LoginResp, error)
}
Go Interfaces are satisfied implicitly.
// auth service must implement the Auther interface
type auth struct {
authSvc Auther
}
// route handler
func(ctr *auth) Login(c echo.Context) error {
var cred * serializers.LoginReq
var resp * serializers.LoginResp
var err error
if err = c.Bind( & cred) err != nil {
return c.JSON(err.Status, err)
}
// the function signature of the service-level Login method must match the interface
if resp, err = ctr.authSvc.Login(cred); err != nil {
return c.JSON(err.Status, err)
}
return c.JSON(http.StatusOK, resp)
}
I like using testify/mock library. Create a Mock.
type MockAuth struct {
mock.Mock
}
func (m *MockAuth) Login(cred *serializers.LoginReq) (*serializers.LoginResp, error) {
args := m.Called(cred)
return args.Get(0).(*serializers.LoginResp), args.Error(1)
}
That's it. Just create a test.
func TestLogin (t *testing.T) {
// setup mocks
cred := &serializers.LoginReq{}
mockReturn := &serializers.LoginResp{}
mockAuth := &MockAuth{}
// setup expectation
mockAuth.On("Login", cred).Return(mockReturn, nil)
// setup server
mux := http.NewServeMux()
mux.HandleFunc("/v1/login", func(w http.ResponseWriter, r *http.Request) {
ec := echo.Context{}
ctr: = &auth {
authSvc: mockAuth
}
ctr.Login(ec)
})
// make request
writer := httptest.NewRecorder()
request, _ := http.NewRequest(http.MethodPost, "/v1/login", "password")
mux.ServeHTTP(writer, request)
// make assertions
mockAuth.AssertExpectations(t)
}
The code above is not 100% correct. I don't use echo myself, however it should get you close. Hope this helps.