Mocking does not work as expected go lang

58 Views Asked by At

I am experiencing the following error

assert: mock: I don't know what to return because the method call was unexpected.
        Either do Mock.On("Send").Return(...) first, or remove the Send() call.
        This method was unexpected:
                Send(services.ConfirmAccountEmail,repository.User)

When consuming real API, it sends the email and mailer.Send is called

So I have an API, which creates Router and routes are registered in Router. Router accepts a parameter of interface mailer in its constructor and thats where I want to tweak which mailer would be used - real or the fake.

The code is as following. I know there's a lot of space for improvement, but now I'm primarily interested in mocking

Mailer interface:

type Mailer interface {
    Send(email Email, receiver User) error
}

Email is also an interface.

The struct that implements Mailer interface:

type EmailDelivery struct {
    Config Config
}

func (service EmailDelivery) Send(email Email, receiver User) error {
    //Code
}

Router code:

type Router struct {
    api         Api
    db          *gorm.DB
    redisClient *redis.Client
    config      Config
    mailer      Mailer
}

func NewRouter(api Api, db *gorm.DB, redisClient *redis.Client, config Config, mailer Mailer) Router {
    return Router{api, db, redisClient, config, mailer}
}

func (router *Router) AddRoutes() {

    router.api.AddRouteWithCors("/register", "POST", WithRequestLog(router.RegisterHandler))
    //...
}


func (router *Router) RegisterHandler(w http.ResponseWriter, r *http.Request) {
            //...

            email := NewConfirmAccountEmail(router.config, "Email subject", "email_template")

            router.mailer.Send(email, user)
}

Api code:

func (api *Api) InitializeRoutes(mailer Mailer) *Router {
    //...
    router := NewRouter(*api, api.db, api.redisClient, config, mailer)
    router.AddRoutes()

    //...
}

Test:

type MockMailer struct {
    mock.Mock
}

func (m *MockMailer) Send(email Email, receiver User) error {
    args := m.Called(email, receiver)
    return args.Error(0)
}

In test:

mailer := new(MockMailer)
mailer.On("Send", mock.Anything, mock.Anything).Return(nil)

//Execute the code that is calling send method - calling endpoint

api := NewApi(config.ServerPort, db, nil)

mailer := new(MockMailer)
router := api.InitializeRoutes(mailer)

req, err := http.NewRequest(http.MethodPost, "/register", bytes.NewReader(body))

w := httptest.NewRecorder()

router.RegisterHandler(w, req)

res := w.Result()

defer res.Body.Close()

mailer.AssertExpectations(t)

//..other expectations

Debugging shows that it entered send method, but I still have this error

Could it be that interface is creating an issue? Or maybe mock.Anything?

Thanks

1

There are 1 best solutions below

2
Dayrion On

The method implemented seems to not be the same as the one in the interface; the parameter types differ: Send(email Email, receiver User) error != Send(services.ConfirmAccountEmail,repository.User).

You may want to check if the implemented structure in the tested structure implements your interface with the correct parameter types.

We lack of information to help you resolve this.