Testing with Gomock returns error: Expected call has already been called the max number of times

12,284

You are implicitly telling gomock that you only expect a single call.

msgr.EXPECT().GetMessage().Return(mq, err)

Adding a number of Times to the mock, allows you to return those values more than once.

msgr.EXPECT().GetMessage().Return(mq, err).AnyTimes()
Share:
12,284
Alwin Doss
Author by

Alwin Doss

I am a tech freak, not to mention I call myself a FOSSite (A Guy who belongs to FOSS movement - Free and Open Source software). Apart from me being a tech freak am passionately in love with Jesus, which got me so interested in FOSS where people share with out greed.

Updated on July 22, 2022

Comments

  • Alwin Doss
    Alwin Doss almost 2 years

    I am using Gomock https://godoc.org/github.com/golang/mock and mockgen

    The Source code for this test is:

    package sqs
    
    import (
        "fmt"
        "log"
        "os"
        "runtime"
    
        "github.com/aws/aws-sdk-go/aws/session"
    
        "github.com/aws/aws-sdk-go/aws"
        "github.com/aws/aws-sdk-go/service/sqs"
        "github.com/aws/aws-sdk-go/service/sqs/sqsiface"
    )
    
    var sess *session.Session
    var svc *sqs.SQS
    var queueURL string
    
    func init() {
        // Setting the runtime to run with max CPUs available
        runtime.GOMAXPROCS(runtime.NumCPU())
    
        sess = session.Must(session.NewSessionWithOptions(session.Options{
            SharedConfigState: session.SharedConfigEnable,
        }))
    
        svc = sqs.New(sess)
    
        queueURL = os.Getenv("QUEUE_URL")
    }
    
    type Poller interface {
        Poll(chan bool)
    }
    
    // NewPoller is a factory to create a Poller object
    func NewPoller(msgr Messenger) Poller {
        p := &poller{
            m: msgr,
        }
        return p
    }
    
    type poller struct {
        m Messenger
    }
    
    func (p *poller) Poll(done chan bool) {
        sqsMsgCh := make(chan *sqs.Message, 100)
        for {
            messages, err := p.m.GetMessage()
            if err != nil {
                log.Printf("error when getting message")
                if len(messages) == 0 {
                    // Stop the system
                    log.Printf("I am here")
                    done <- true
                }
            }
            for _, msg := range messages {
                sqsMsgCh <- msg
            }
        }
    }
    
    type Messenger interface {
        GetMessage() ([]*sqs.Message, error)
    }
    
    func NewMessenger() Messenger {
        return &messenger{
            s: svc,
        }
    }
    
    type messenger struct {
        s sqsiface.SQSAPI
    }
    
    func (m *messenger) GetMessage() ([]*sqs.Message, error) {
        result, err := m.s.ReceiveMessage(&sqs.ReceiveMessageInput{
            AttributeNames: []*string{
                aws.String(sqs.MessageSystemAttributeNameSentTimestamp),
            },
            MessageAttributeNames: []*string{
                aws.String(sqs.QueueAttributeNameAll),
            },
            QueueUrl:            aws.String(queueURL),
            MaxNumberOfMessages: aws.Int64(10),
            VisibilityTimeout:   aws.Int64(36000), // 10 hours
            WaitTimeSeconds:     aws.Int64(0),
        })
    
        if err != nil {
            fmt.Println("Error", err)
            return nil, err
        }
    
        msgs := result.Messages
        if len(msgs) == 0 {
            fmt.Println("Received no messages")
            return msgs, err
        }
        return msgs, nil
    }
    

    The test case for this Source file is here:

    package sqs
    
    import (
        "errors"
        "testing"
    
        "path_to_the_mocks_package/mocks"
        "github.com/golang/mock/gomock"
    
        "github.com/aws/aws-sdk-go/service/sqs"
    )
    
    
    func TestPollWhenNoMessageOnQueue(t *testing.T) {
        mockCtrl := gomock.NewController(t)
        defer mockCtrl.Finish()
    
        msgr := mocks.NewMockMessenger(mockCtrl)
        mq := make([]*sqs.Message, 1)
        err := errors.New("Mock Error")
        // msgr.EXPECT().GetMessage().Return(mq, err) //.Times(1)
        // msgr.GetMessage().Return(mq, err) //.Times(1)
        msgr.EXPECT().GetMessage().Return(mq, err)
    
        p := NewPoller(msgr)
        done := make(chan bool)
        go p.Poll(done)
        <-done
        t.Logf("Successfully done: %v", done)
    }
    

    When I run the tests I am getting the following error:

    sqs\controller.go:150: Unexpected call to *mocks.MockMessenger.GetMessage([]) at path_to_mocks_package/mocks/mock_messenger.go:38 because: Expected call at path_to_sqs_package/sqs/sqs_test.go:35 has already been called the max number of times. FAIL

    If I write my own mock as follows the test case executes successfully:

    type mockMessenger struct {
        mock.Mock
    }
    
    func (m *mockMessenger) GetMessage() ([]*sqs.Message, error) {
        msgs := make([]*sqs.Message, 0)
        err := errors.New("Error")
        return msgs, err
    }