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

150 Views Asked by At

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)
}
1

There are 1 best solutions below

0
Elias Van Ootegem On BEST ANSWER

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.