So currently I have a http handler that looks like:
type App struct {
}
func (a *App) someHandler(w http.ResponseWriter, r *http.Request) {
var api = slack.New("TOKEN")
users = api.GetUsers()
}
I want to create an interface for this slack.New("...") call so that in my tests the api doesn't make network requests to slack.
How can I mock this New call?
The call New("TOKEN") returns a *Client, see the link below:
func New(token string, options ...Option) *Client {
s := &Client{
token: token,
httpclient: &http.Client{},
log: log.New(os.Stderr, "nlopes/slack", log.LstdFlags|log.Lshortfile),
}
for _, opt := range options {
opt(s)
}
return s
}
https://github.com/nlopes/slack/blob/0f8db5050731c50359e319cf253af5b9997a2b1e/slack.go#L84
I haven't used interfaces that much so not sure if this can't be put in a interface since the call to New is like a constructor?
You can't mock the slack.New
call itself, instead you have to create a mock that behaves like this api
object. To do this put the api
onto the App
struct but as an interface:
type SlackClient interface {
GetUsers() []string
}
type App struct {
api SlackClient
}
func (a *App) someHandler(w http.ResponseWriter, r *http.Request) {
users = a.api.GetUsers()
}
You then have to move the call to slack.New
into whatever constructs the App
(for instance your main function or a NewApp
constructor function):
app = App{api: slack.New("TOKEN")}
The *Client this returns has a GetUsers
method on it so will match the interface we have defined.
The test then does something similar with a mock:
type mockSlackClient struct {
}
func (m *mockSlackClient) GetUsers() []string {
return nil
}
func TestSomeHandler(t *testing.T) {
appToTest := App{api: &mockSlackClient{})
appToTest.someHandler(httptest.NewRecorder(), nil)
}
Again as the *mockSlackClient
has a GetUsers
method on it it will satisfy the interface so you will be able to use it on the App
.