testify icon indicating copy to clipboard operation
testify copied to clipboard

How do I mock a function that write result to it's argument in Go

Open mong0520 opened this issue 5 years ago • 6 comments

Suppose I have a method below,

func DoSomething(result interface{}) error {
    // write some data to result
    return nil
}

so the caller can call DoSomething as following

result := &SomeStruct{}
err := DoSomething(result)

if err != nil {
  fmt.Println(err)
} else {
  fmt.Println("The result is", result)
}

Now I know how to use testify or some other mocking tools to mock the returns value (it's err here) by something like

mockObj.On("DoSomething", mock.Anything).Return(errors.New("mock error"))

My question is "how do i mock the result argument" in this kind of scenario?

Since result is not a return value but a argument, the caller calls it by passing a pointer of a struct, and the function modify it.

Just like what https://godoc.org/github.com/golang/mock/gomock#Call.SetArg do

mong0520 avatar Apr 07 '20 03:04 mong0520

I have the same question

tiagoamorim85 avatar Apr 29 '20 10:04 tiagoamorim85

I use mockery so that you can pass a function(instead of a particular value) to Return in which you can do whatever you want with the data you passed. For example:

mockObj.On("DoSomething", mock.Anything).Return(func(input *SomeStruct) error {
    input.field = some_value
    return errors.New("mock error")
})

revilwang avatar May 06 '20 03:05 revilwang

Are you not able to pass in the argument through the second parameter of the On() function?

e.g. mockObj.On("DoSomething", resultInputArgument).Return(errors.New("mock error"))?

boyan-soubachov avatar May 06 '20 08:05 boyan-soubachov

A bit late but you could also do a mock.MatchedBy

Something like:

mockObj.On("DoSomething", mock.MatchedBy(func(s *SomeType) bool {
	s.field = some_value
	return true
})).Return(nil)

guillaq avatar Mar 15 '21 11:03 guillaq

I have the same question still unable to solve it.

durgeshatal avatar Sep 12 '22 12:09 durgeshatal

This is what Run() is for, playground:

package main

import (
	"testing"

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

type MyStruct struct {
	V string
}

type MyClass struct {
	mock.Mock
}

func (m *MyClass) DoSomething(arg *MyStruct) error {
	return m.Called(arg).Error(0)
}

func TestTestify(t *testing.T) {
	s := &MyStruct{}
	m := &MyClass{}
	m.On("DoSomething", mock.AnythingOfType("*main.MyStruct")).Run(func(args mock.Arguments) {
		arg := args.Get(0).(*MyStruct)
		arg.V = "hello"
	}).Return(nil)
	err := m.DoSomething(s)
	assert.NoError(t, err)
	assert.Equal(t, "hello", s.V)
}

Do not use MatchedBy() to try to achieve this, it might be called more than once.

brackendawson avatar Sep 12 '22 15:09 brackendawson