Is it possible to mock a function imported from a package in golang?

前端 未结 3 1588
旧时难觅i
旧时难觅i 2020-12-23 10:18

I have the following method to test, which uses a function imported from a package.

import x.y.z

func abc() {
    ...
    v := z.SomeFunc()
    ... 
}


        
相关标签:
3条回答
  • 2020-12-23 10:25

    Yes, with a simple refactoring. Create a zSomeFunc variable of function type, initialized with z.SomeFunc, and have your package call that instead of z.SomeFunc():

    var zSomeFunc = z.SomeFunc
    
    func abc() {
        // ...
        v := zSomeFunc()
        // ...
    }
    

    In tests you may assign another function to zSomeFunc, one that is defined in tests, and does whatever the test wants it to.

    For example:

    func TestAbc(t *testing.T) {
        // Save current function and restore at the end:
        old := zSomeFunc
        defer func() { zSomeFunc = old }()
    
        zSomeFunc = func() int {
            // This will be called, do whatever you want to,
            // return whatever you want to
            return 1
        }
    
        // Call the tested function
        abc()
    
        // Check expected behavior
    }
    

    See related / possible duplicate: Testing os.Exit scenarios in Go with coverage information (coveralls.io/Goveralls)

    0 讨论(0)
  • 2020-12-23 10:33

    Having function pointer and monkey patching it is the one of doing it. But then when you multiple functions to mock, you will have a number function pointers and unnecessarily you will have to call function using the function pointer only.

    The better and the recommended idea to have an interface and make your function part of the struct implementing the interface. Once done that, you can generate mocks using some nice tools available for go.

    I have been using this:

    mockgen -source myModule.go -package myPackage -destination myModuleMock.go
    

    You can install it by:

    got get github.com/golang/mock
    
    0 讨论(0)
  • 2020-12-23 10:38

    One thing you can do is this:

    import "x/y/z"
    
    var someFunc = z.SomeFunc
    
    func abc() {
        ...
        v := someFunc()
        ... 
    }
    

    And in your test file you would do this.

    func Test_abc() {
        someFunc = mockFunc
        abc()
    }
    

    But make sure that you do this in a concurrent manner, if you have multiple TestXxx functions calling abc or setting someFunc you may be better of using a struct with a someFunc field.

    0 讨论(0)
提交回复
热议问题