3

I am trying to mock the below method using gomock

func (w *writer) Publish(vacancies []model.Vacancy) error {
    ...

    if _, err = w.conn.WriteMessages(msg); err != nil {
        return fmt.Errorf("failed to write message: %w", err)
    }

Interface:

type Producer interface {
        Publish(vacancies []model.Vacancy) error
        Close() error
    }

SuiteTest:

func (p *ProducerTestSuite) SetupTest() {
    p.mockCtrl = gomock.NewController(p.T())
    p.producer = NewMockProducer(p.mockCtrl)
    writer, err := producer.NewWriter(context.Background(), scheduler.KafkaConf{Addr: "localhost:9092", Topic: "test"})
    p.Require().NoError(err)
    p.writer = writer
}
...
func (p *ProducerTestSuite) TestProducer_Publish() {
    p.producer.EXPECT().Publish([]model.Vacancy{}).Return(nil)
    p.Require().NoError(p.writer.Publish([]model.Vacancy{}))
}

mockgen:

//go:generate mockgen -package producer_test -destination mock_test.go -source ../kafka.go

When I try run test, I got this message:

=== RUN   TestSuite/TestProducer_Publish
    controller.go:137: missing call(s) to *producer_test.MockProducer.Publish(is equal to [] ([]storage.Vacancy)) /Users/...
    controller.go:137: aborting test due to missing call(s)

Where I wrong?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Ramil Kuvatov
  • 43
  • 1
  • 1
  • 4
  • I see no code which would actually call `Publish` on anything—just setting up a mock. – kostix Aug 15 '21 at 17:58
  • p.Require().NoError(**p.writer.Publish([]model.Vacancy{})**) – Ramil Kuvatov Aug 15 '21 at 18:11
  • Thanks, I see now. May it be that the problem is that you're calling `producer.NewWriter` anfd not `p.producer.NewWriter`? I mean, I would expect that you would obtain a new writer on a mock producer instance. With the code as presented, it looks like the created `writer` has no connection with the producer's mock. – kostix Aug 15 '21 at 19:14
  • probably I solved it . https://goplay.space/#bNvv5N9QFjF – Ramil Kuvatov Aug 15 '21 at 20:52

4 Answers4

4

This answer is late, but it might helpful.

To require the function to be called once:

mockService.EXPECT().DoSomething().Return(nil, nil)

To allow the function to be called zero or more times:

mockService.EXPECT().DoSomething().Return(nil, nil).AnyTimes()
TaQuangTu
  • 2,155
  • 2
  • 16
  • 30
2

the Expect() means these must be a call to this method with the specified parameter, otherwise it will be failed, the missing call means your set a Expect() but didn't call it.

enter image description here

Robin
  • 543
  • 1
  • 6
  • 12
1

It appears as if you are not calling the same thing that you are expecting on. Your expect is watching p.producer.Publish(), but your test code calls p.writer.Publish(). I cannot see any code here that would lead writer to call anything in producer.

The following code would behave as you expect:

func (p *ProducerTestSuite) TestProducer_Publish() {
    p.producer.EXPECT().Publish([]model.Vacancy{}).Return(nil)
    p.Require().NoError(p.producer.Publish([]model.Vacancy{}))
}

However, this test does not seem to actually exercise the unit that the test name indicates it should. Perhaps you are misunderstanding mocking ?

Noah Stride
  • 402
  • 2
  • 9
1

I also resolved a similar issue by adding a:

EXPECT().<interface-method>().Return(...).AnyTimes()

It seems that if one sets an EXPECT() gomock assumes that it must be called at least once. Adding AnyTimes() allows it to be called 0 times.

antonbiz
  • 11
  • 1