简体   繁体   中英

Mocking a inner function(or even more deep) for testing in go

is there a way to achieve this? I want to Mock the response of a function call from within another function call. Example

main.go

type Crs struct {}
func (cr crs)TheFunction() error {
   // Some code
   _ := ToMockResponse(hello string)
   return nil
}

func ToMockResponse() error {
    return somerror
}

and in my test file

main_test.go

func TestTheFunction(t *testing.T) {
    cr = Crs{}
    mockInstance = new(randomMock)
    mockInstance.On("ToMockResponse").Return(nil)

    err := cr.TheFunction()
    assert.NoError(t, err)
}

I'm not sure if what I did is correct. What I'm trying to achieve is that I just want to have a Mock response of ToMockResponse whenever it's being called inside TheFunction

I have seen and read most of the tutorial but all of them shows a Mock response from a method of a class. But there are no function-to-function mocking samples. Hope you can provide a solution to this.

Without getting into whether you should do this, and assuming that you have a valid reason to do so, one way to mock functions is to use them via a level of indirection. You can then substitute a suitable alternative in your indirection for the purposes of testing.

An interface is one way to achieve that, but GoLang supports functions as values, so another way is to use a simple variable of an appropriate function type:

Adapted to your example, this might look similar to:

var toMockResponse = ToMockResponse

func (cr crs)TheFunction() error {
   // Some code
   _ := toMockResponse(hello string)
   return nil
}

func ToMockResponse() error {
    return somerror
}

and your test:

func TestTheFunction(t *testing.T) {
    cr = Crs{}
    ofn := toMockResponse
    toMockResponse = func(string) error { return nil }
    defer func() { toMockResponse = ofn }()

    err := cr.TheFunction()
    assert.NoError(t, err)
}

I have assumed that you need to export the ToMockResponse ; the function variable is deliberately not exported so that it cannot be manipulated outside of the package itself.

If the function being redirected is itself not exported, denying the ability to use the case difference of exported vs non-exported symbols to differentiate them, then you may need to be a bit more creative with your naming. eg a variable called toMockResponseFn .

Footnote

ofn is mnemonic for "original function". In a more complicated test you can preserve the pattern by creating a scope for each ofn you need ( defer operates w.r.t the containing function, not the scope):

   {
      ofn := toMockResponse
      toMockResponse = func(string) error { return nil }
      defer func() { toMockResponse = ofn }()
   }
   {
      ofn := now
      now = func() time.Time { return time.Date(..etc..) }
      defer func() { now = ofn }()
   }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM