Search code examples
gotestingtestify

How can I mock a function with no input or output in testify?


I'm currently unit testing a piece of code which uses an interface that contains a method with no input or output. Using testify's mock package, what is the proper way to write a mock implementation of this function?

Currently, I've written it as:

type A struct {
  mock.Mock
}

func (a *A) DoSomething() {
_ = a.Called(nil)
}

Solution

  • Let's say you have something like this:

    package foo
    
    type Foo struct {}
    
    func New() *Foo {
        return &Foo{}
    }
    
    func (f *Foo) Called() {
        fmt.Println("no in/output, does something here")
    }
    
    package bar
    
    type Dependency interface {
        Called() // the dependency you want to make sure is called
    }
    
    type Svc struct {
        dep Dependency
    }
    
    func New(d Dependency) *Svc {
        return &Svc{
            dep: d,
        }
    }
    
    func (s *Svc) Something() {
        s.dep.Called()
    }
    

    Now, using mockgen as outlined in this related answer of mine we can add the following bit:

    package bar
    
    //go:generate go run github.com/golang/mock/mockgen -destination mocks/deps_mock.go -package mocks your.mod/path/to/pkg/bar Dependency
    type Dependency interface {
        Called() // the dependency you want to make sure is called
    }
    
    type Svc struct {
        dep Dependency
    }
    
    func New(d Dependency) *Svc {
        return &Svc{
            dep: d,
        }
    }
    
    func (s *Svc) Something() {
        s.dep.Called()
    }
    

    This will generate a package under bar (as in bar/mocks), which contains the generated mock/fake/spy object you'll want to use in your test like this:

    package bar_test
    
    import (
        "testing"
    
        "your.mod/path/to/bar"
        "your.mod/path/to/bar/mocks"
    
        "github.com/golang/mock/gomock"
    )
    
    func TestSomething(t *testing.T) {
        ctrl := gomock.NewController(t)
        defer ctrl.Finish() // this is when the expected calls are checked
        dep := mocks.NewMockDependency(ctrl) // create the instance of the mock/spy
        svc := bar.New(dep) // pass in the spy
        dep.EXPECT().Called().Times(1)
        svc.Something() // the test will pass if the call was made
    
        // alternatively, you can log some output, too:
        dep.EXPECT().Called().Times(1).Do(func() {
            // this gets called as though it was s.Called() in your code
            t.Log("The dependency was called as expected")
        })
        svc.Something()
    }
    

    mockgen/gomock can do a lot more than just this, read more about it here. It seems like the repo was recently archived and moved, I suspect its replacement is pretty much a drop in replacement + some new functionality though.