MadzQuestioning
MadzQuestioning

Reputation: 3772

Testify Mock a function return inside a function

I would like to Mock the response of a function. But this function is located or called inside another function. Let say I have this function

// main.go
func TheFunction() int {
   // Some code
   val := ToMockResponse()
   return val
}

func ToMockResponse() int {
    return 123
}

Now on my test file

// main_test.go
func TestTheFunction(t *testing.T) {
    mockInstance = new(randomMock)
    mockInstance.On("ToMockResponse").Return(456)

    returned := TheFunction()
    assert.Equal(t, 456, returned)
}

As you can see within function TheFunction() a call to function ToMockResponse is made. Now I would like to test TheFunction but I would like to Mock the response of ToMockResponse how can I achieve this?

Upvotes: 3

Views: 3258

Answers (2)

Chandan
Chandan

Reputation: 742

Let's consider we have two functions, executor() and process() where executor function calls process function,

We need to write both the functions as shown below with structures and interfaces:

main.go is as shown below:

package main

import "fmt"

// A structure defined which will have a value of type processHandler(interface)
// This is helpful  to pass a structure instance of processData later(see in main function)
// This is required to pass mock instance also
type processDataHandler struct{ procData processHandler }

// Interface defined for process method
type processHandler interface {
    process() (int, string)
}

// structure on top of which executor method is getting called
type processData struct{}

// process method called by executor method
func (p processData) process() (int, string) {
    return 23, "test2"
}

// executor method which has "processDataHandler" as argument
func (e processDataHandler) executor() (int, string) {
    // Some code
    //process function call
    val, str_val := e.procData.process()
    if val == 23 {
        return 40, "success"
    }
    return 45, str_val
}

func main() {
    procData := processData{}
    dataHandle := processDataHandler{procData: procData}
    val1, val2 := dataHandle.executor()

    fmt.Println(val1)

    fmt.Println(val2)

}

main_test.go is as shown below:

package main

import (
    "testing"

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

//Define a mock insatnce
type processDataMock struct {
    mock.Mock
}

func (m *processDataMock) process() (int, string) {
    // this records that the method was called and passes in the value
    // it was called with
    args := m.Called()
    // it then returns whatever we tell it to return
    // in this case we are returing a integer type followed by a string type
    return args.Int(0), args.String(1)
}

//Test function for executor method
func TestExecutor(t *testing.T) {
    //define mock instance
    procMock := new(processDataMock)
    //Make process function to return 1 and "test" via mock
    procMock.On("process").Return(1, "test")
    //create a processDatahandler with mock instance
    handler := processDataHandler{procData: procMock}
    //call executor function which inturn mocks process via "procMock.On" above
    a, b := handler.executor()

    assert.Equal(t, 45, a)
    assert.Equal(t, "test", b)

}

Upvotes: 0

dolan
dolan

Reputation: 1804

You should consider passing in the second function is as an parameter to the first.

You have a few options for doing that. You could simply pass it as a parameter.

func DoX(doY func()) {
   doY()
}

That’s simple but doesn’t work well as the core get more complex. The better alternative is often to make the functions methods on a struct.

type X struct {
   Y Y
}

type Y interface {
   Do()
}

func (x *X) Do() {
   x.Y.Do()
}

Then Y can be replaced with a mock.

Upvotes: 1

Related Questions