3

Hi I'm trying to mock a struct in GO. I'm using testify to do this. But I can't seem to get it to work and don't now what I'm doing wrong. Below is the sample main.go and main_test.go file I have

// Arithmetic ...
type Arithmetic interface {
    Add(int, int) int
    Subtract(int, int) int
}

// MathOperation ...
type MathOperation struct {}

// GetNewArithmetic ...
func GetNewArithmetic(obj Arithmetic) Arithmetic {
    if obj != nil {
        return obj
    }

    return MathOperation{}
}

// Add ...
func (a MathOperation) Add(num1 int, num2 int) int {
    return num1 + num2
}

// Subtract ...
func (a MathOperation) Subtract(num1 int, num2 int) int {
    return num1 - num2
}

And here is my test file

import (
    "testing"

    "github.com/stretchr/testify/assert"
    "github.com/stretchr/testify/mock"
)

type MyMock struct {
    mock.Mock
}

func (m *MyMock) Add(num1 int, num2 int) int {
    args := m.Called(num1, num2)
    return args.Int(0) + args.Int(1)
}

func (m *MyMock) Subtract(num1 int, num2 int) int {
    args := m.Called(num1, num2)
    return args.Int(0) + args.Int(1)
}

func TestDoComputation(t *testing.T) {
    testobj := new(MyMock)

    testobj.On("Add", 1, 2).Return(5)

    // a := GetNewArithmetic(testobj)

    result := GetNewArithmetic(testobj)

    assert.Equal(t, 5, result.Add(5, 6))
    testobj.AssertExpectations(t)
}

I receive this error

--- FAIL: TestDoComputation (0.00s)
panic:

mock: Unexpected Method Call
-----------------------------

Add(int,int)
            0: 5
            1: 6

The closest call I have is:

Add(int,int)
            0: 1
            1: 2


 [recovered]
        panic:

mock: Unexpected Method Call
-----------------------------

Add(int,int)
            0: 5
            1: 6

The closest call I have is:

Add(int,int)
            0: 1
            1: 2

goroutine 13 [running]:
testing.tRunner.func1(0xc420106870)
        /usr/lib/golang/src/testing/testing.go:711 +0x2d2
panic(0x701160, 0xc420011070)

I have no idea on how to fix since this is my first time using Go and using Testify to do unit testing. Would appreciate if someone can take a look and have a working version of this. Thanks

MadzQuestioning
  • 3,341
  • 8
  • 45
  • 76
  • 3
    `testobj.On("Add", 1, 2).Return(5)` = expect a call to `Add` with arguments `1` and `2` and return value `5`. The actuall call `result.Add(5, 6)` passes `5` and `6`. These two numbers, as you know, are not the same as `1` and `2`. – mkopriva Jun 09 '18 at 09:03
  • 1
    Also you mock is calculating the result `return args.Int(0) + args.Int(1)` as a normal implementation would. That's not how you do mocks. Your mock should return it's 0th return value, the one you passed to the `Return` method (`5`). So the mocks return statement should actually be `return args.Int(0)`. <- return the zeroeth return arguemnt as an int. – mkopriva Jun 09 '18 at 09:07
  • 1
    Also, do understand that the `args` value holds the specified *return* arguemnts (those passed to the `Return` method), the `args` value *does not* hold the input arguments. – mkopriva Jun 09 '18 at 09:11
  • i.e. https://play.golang.org/p/5PA15xsMXYM – mkopriva Jun 09 '18 at 09:14
  • @mkopriva thanks a lot for pointing out this parameter and arguments. Because honestly I have no idea what it does, I just copied and did some modification from an online tutorial. Thanks for clarifying this. Can you move your answer to actual answer so that I can approve this as a solution – MadzQuestioning Jun 09 '18 at 09:20
  • When this is the first time you use Go, then just stay away from fancy tooling like Testify! Write plain and simple test. Do not try fancy stuff just because such stuff is en vogue in your prior languages. – Volker Jun 09 '18 at 20:21

2 Answers2

7

The line

testobj.On("Add", 1, 2).Return(5)

means that you expect the testobj mock to receive a call to its Add method with arguments 1 and 2 passed to it, and you also specify that that call should return the integer value 5.

But instead on this line

assert.Equal(t, 5, result.Add(5, 6))

you are calling the method Add with arguments 5 and 6.

This results in the error you got:

mock: Unexpected Method Call
-----------------------------

Add(int,int)
            0: 5
            1: 6
// this is result.Add(5, 6), the 0: and 1: are indexes of the actually passed in aguments.

The closest call I have is:

Add(int,int)
            0: 1
            1: 2
// this is testobj.On("Add", 1, 2), and 0: and 1: are indexes of the expected arguments.

On top of that your mock implementations are attempting to calculate and return the value. This is not what a mock should do. A mock should instead return the value provided to it through the Return method.

The way you can do this is by using the args value returned from the Called method call, this value will hold the Return method's arguments indexed in the same order they were passed in to Return.

So the integer value 5 that you passed to Return on this line

testobj.On("Add", 1, 2).Return(5)

can be accessed using the Int utility method and passing it the 0th index. That is return args.Int(0) will return the interger value 5.

So your test file should look more like this:

import (
    "testing"

    "github.com/stretchr/testify/assert"
    "github.com/stretchr/testify/mock"
)

type MyMock struct {
    mock.Mock
}

func (m *MyMock) Add(num1 int, num2 int) int {
    args := m.Called(num1, num2)
    return args.Int(0)
}

func (m *MyMock) Subtract(num1 int, num2 int) int {
    args := m.Called(num1, num2)
    return args.Int(0)
}

func TestDoComputation(t *testing.T) {
    testobj := new(MyMock)

    testobj.On("Add", 1, 2).Return(5)

    // a := GetNewArithmetic(testobj)

    result := GetNewArithmetic(testobj)

    assert.Equal(t, 5, result.Add(1, 2))
    testobj.AssertExpectations(t)
}
mkopriva
  • 35,176
  • 4
  • 57
  • 71
2

In testify/mock package

testobj.On("Add", 1, 2).Return(5)

In above line,It tell the mock object that whenever we Call Add method with following arguments,it should return 5. Return is used to pass the result to the method with the given arguments.

assert.Equal(t, 5, result.Add(5, 6))

In this line,you are asking to match the expected result with the function call.Earlier you specify when you pass 1 & 2,the function should return 5 but in Equal statement you are passing values 5 & 6

All you have to is the change any of the one line with the correct value.

testobj.On("Add", 5, 6).Return(5)