stretchr / testify

A toolkit with common assertions and mocks that plays nicely with the standard library
MIT License
23.11k stars 1.58k forks source link

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

Open mong0520 opened 4 years ago

mong0520 commented 4 years ago

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

tiagoamorim85 commented 4 years ago

I have the same question

revilwang commented 4 years ago

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")
})
boyan-soubachov commented 4 years ago

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"))?

guillaq commented 3 years ago

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)
durgeshatal commented 2 years ago

I have the same question still unable to solve it.

brackendawson commented 2 years ago

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.