I am using testify to test my code and I want to check if a function was called.
I am doing the following:
type Foo struct {
mock.Mock
}
func (m Foo) Bar() {
}
func TestFoo(t *testing.T) {
m := Foo{}
m.Bar()
m.AssertCalled(t, "Bar")
}
The error I am getting:
Error: Should be true
Messages: The "Bar" method should have been called with 0 argument(s), but was not.
mock.go:419: []
I call function "Bar" and immediately ask if it was called but it returns false.
What am I doing wrong?
What is the proper way to test if a function was called with testify?
I tried with this and works:
type Foo struct {
mock.Mock
}
func (m *Foo) Bar() {
m.Called()
}
func TestFoo(t *testing.T) {
m := &Foo{}
m.On("Bar").Return(nil)
m.Bar()
m.AssertCalled(t, "Bar")
}
As stated by Chris Drew, you've to use a receiver pointer on Bar method's declaration.
Additionally, you've to istantiate a new structure as pointer and mock the method to return a value.
Looking at the documentation of testify I think you have to explicitly call func (*Mock) Called to tell the mock object that a method has been called.
func (m *Foo) Bar() {
m.Called()
}
There are some examples in the testify tests.
Make sure it is pointer receiver NOT value receiver.
This will always have nil Calls
type Foo struct {
mock.Mock
}
func (m Foo) Bar()
m.Called()
}
This will have N number of Calls
type Foo struct {
mock.Mock
}
func (m *Foo) Bar()
m.Called()
}
As an additional solution for when you want/need to use a value receiver, though not as clean, specifying Mock as a pointer field worked for me.
type Foo struct {
m *mock.Mock
}
func (f Foo) Bar() {
f.m.Called()
}
func TestFoo(t *testing.T) {
f := Foo{m: &mock.Mock{}}
f.Bar()
f.m.AssertCalled(t, "Bar")
}
Related
Let's say I have this code and I want to create a test for Foo()
The important part it Foo makes a call to Bar
package main
type MyInterface interface {
Foo() error
Bar() error
}
type MyStruct struct {
}
func NewMyStruct() MyInterface{
return &MyStruct{}
}
func (m *MyStruct) Foo() error {
// do something
m.Bar()
// do something else
return nil
}
func (m *MyStruct) Bar() error {
// do something
return nil
}
Is it possible to create a test for this where I can mock the behaviour of Bar before I run Foo? or am I doing something fundamentally wrong?
I can see that if I extracted Bar into its own service I would mock it that way but that also doesn't feel right.
Any insights or links to documentation would be great.
You should be able to achieve what you need with a couple of changes. First, let me present the code and then I'll walk you through all of the relevant changes.
main.go file
package main
type MyInterface interface {
Foo() error
Bar() error
}
type MyStruct struct {
DS MyInterface
}
// here you've to depend upon an interface and return a pointer to a struct
func NewMyStruct(ds MyInterface) *MyStruct {
return &MyStruct{
DS: ds,
}
}
func (m *MyStruct) Foo() error {
// do something
m.DS.Bar()
// do something else
return nil
}
func (m *MyStruct) Bar() error {
// do something
return nil
}
func main() {}
Here, I changed a couple of things in order to be able to successfully mock our dependencies. Let me recap them:
The MyStruct has a dependency of type MyInterface
The function NewMyStruct accepts the interface as parameter and returns a pointer to the MyStruct struct
In the Foo method, we're going to rely on the DS field of our pointer receiver type instance
Now, let's switch to the test file.
main_test.go file
package main
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
// 1. declare mock
type myStructMock struct {
mock.Mock
}
// 2. implement the interface
func (m *myStructMock) Foo() error {
args := m.Called()
return args.Error(0)
}
func (m *myStructMock) Bar() error {
args := m.Called()
return args.Error(0)
}
func TestFoo(t *testing.T) {
// 3. instantiate/setup mock
myStructMock := new(myStructMock)
myStructMock.On("Bar").Return(nil).Times(1)
sut := NewMyStruct(myStructMock)
err := sut.Foo()
// 4. check that all expectations were met on the mock
assert.Nil(t, err)
assert.True(t, myStructMock.AssertExpectations(t))
}
Here, I found it best to add comments within the code to give you a chronological order of what's going on. The idea is that the real system tested (e.g. the sut variable) is relying on mock instead of actual implementations. Thanks to the method Times, we make sure that the Bar method is called once.
I always used this approach when it comes to testing production code and I find it pretty flexible and amazing!
Let me know if this helps you or if you still need something else, thanks!
I'm modeling the state machine implementation outlined in this talk by Rob Pike https://www.youtube.com/watch?v=HxaD_trXwRE&t=1830s
and I'm not able to get it to compile. I've provided a small sample that fails.
The call: m := New(foo)
fails with
./main.go:31:11: undefined: foo
I've tried
m := New(M.foo)
m := New(foo(*M))
I don't know the proper syntax for this.
package main
type StateFunc func(*M) StateFunc
type M struct {
start StateFunc
}
func New(start StateFunc) *M {
return &M{
start: start,
}
}
func (m *M) foo() StateFunc {
return nil
}
func (m *M) Start() {
go m.run()
}
func (m *M) run() {
state := m.start
for state != nil {
state = state(m)
}
}
func main() {
m := New(foo)
}
I would expect it to compile but I don't know the proper syntax to make this work.
the method (m *M) foo() doesn't match the signature of type StateFunc func(*M) StateFunc
foo is a method, it has a receiver *M, you can't use it without the receiver.
my suggestion is to modify foo:
func foo(*M) StateFunc {
return nil
}
I need a little help with mocking struct member functions in Go.
Here is the specific use case:
I have a struct Foo with a field which represents some internal state of the struct instance. This struct also has two member functions Bar() and Baz(). I want to test Baz() while mocking out Bar().
Thank you for your help.
package awesomeProject
import "fmt"
type Foo struct {
state string
}
func NewFoo(s string) *Foo {
return &Foo{s}
}
func (f *Foo) Bar() {
fmt.Println(f.state)
}
func (f *Foo) Baz() {
if len(f.state) > 0 {
f.Bar()
}
}
Should I check for nil values in the constructor and then set an unexported struct field, or make the default struct value useful by checking for nil at method level?
type Foo struct{}
func (f *Foo) Baz() {}
var DefaultFoo = new(Foo)
type Bar struct {
Foo *Foo
}
func (b *Bar) Baz() {
if b.Foo == nil {
DefaultFoo.Baz()
} else {
b.Foo.Baz()
}
}
or
type Foo struct{}
func (f *Foo) Baz() {}
var DefaultFoo = new(Foo)
type Bar struct {
foo *Foo
}
func NewBar(foo *Foo) *Bar {
if foo == nil {
foo = DefaultFoo
}
return &Bar{foo}
}
func (b *Bar) Baz() {
b.foo.Baz()
}
I don't think there is a "right" answer for this.
Having said this, the approach usually seen in the Go base libraries is letting the objects be created without any constructor, with nil or zero values in its fields, and then make the methods have logic to use or return useful defaults.
Take a look at the http.Client implementation for example:
https://github.com/golang/go/blob/master/src/net/http/client.go
It will basically let you create a new client by just doing:
client := &http.Client{}
You can then populate the fields of the object if you want to override defaults, otherwise it'll check for nil in different methods to provide default behaviour, for example:
https://github.com/golang/go/blob/master/src/net/http/client.go#L195
func (c *Client) transport() RoundTripper {
if c.Transport != nil {
return c.Transport
}
return DefaultTransport
}
So I'd like to have a map of names of functions, to choose an implementation of an interface based on an environment variable. I've reproduced it in the following code:
package test
type Fooer interface {
Foo() error
}
type Bar struct{}
func NewBar() (*Bar, error) { return &Bar{}, nil }
func (b *Bar) Foo() error { return nil }
type Baz struct{}
func NewBaz() (*Baz, error) { return &Baz{}, nil }
func (b *Baz) Foo() error { return nil }
var constructors map[string]func() (*Fooer, error)
func init() {
constructors = map[string]func() (*Fooer, error){
"bar": NewBar,
"baz": NewBaz,
}
}
This throws the following errors when I go build test.go:
./test.go:21: cannot use NewBar (type func() (*Bar, error)) as type func() (*Fooer, error) in map value
./test.go:22: cannot use NewBaz (type func() (*Baz, error)) as type func() (*Fooer, error) in map value
So what am I doing wrong? Can I use a *Fooer as the return type of a constructor function? What would be the actual best way to approach this? (I'm new to Go)
Do not (almost never) pass around pointers to interface. You will (almost) never need a *Fooer, a Fooer is enough.
Yes, your Bar and Baz constructors could return a Fooer (not a *Fooer!) but that seems awkward.
Keeping the constructors in a map and querying the map for a constructor seem like one level of indirection too much. Are you constantly creating new Bar and Baz?