Giter Club home page Giter Club logo

mock's Introduction

gomock

Update, June 2023: This repo and tool are no longer maintained. Please see go.uber.org/mock for a maintained fork instead.

Build Status Go Reference

gomock is a mocking framework for the Go programming language. It integrates well with Go's built-in testing package, but can be used in other contexts too.

Installation

Once you have installed Go, install the mockgen tool.

Note: If you have not done so already be sure to add $GOPATH/bin to your PATH.

To get the latest released version use:

Go version < 1.16

GO111MODULE=on go get github.com/golang/mock/[email protected]

Go 1.16+

go install github.com/golang/mock/[email protected]

If you use mockgen in your CI pipeline, it may be more appropriate to fixate on a specific mockgen version. You should try to keep the library in sync with the version of mockgen used to generate your mocks.

Running mockgen

mockgen has two modes of operation: source and reflect.

Source mode

Source mode generates mock interfaces from a source file. It is enabled by using the -source flag. Other flags that may be useful in this mode are -imports and -aux_files.

Example:

mockgen -source=foo.go [other options]

Reflect mode

Reflect mode generates mock interfaces by building a program that uses reflection to understand interfaces. It is enabled by passing two non-flag arguments: an import path, and a comma-separated list of symbols.

You can use "." to refer to the current path's package.

Example:

mockgen database/sql/driver Conn,Driver

# Convenient for `go:generate`.
mockgen . Conn,Driver

Flags

The mockgen command is used to generate source code for a mock class given a Go source file containing interfaces to be mocked. It supports the following flags:

  • -source: A file containing interfaces to be mocked.

  • -destination: A file to which to write the resulting source code. If you don't set this, the code is printed to standard output.

  • -package: The package to use for the resulting mock class source code. If you don't set this, the package name is mock_ concatenated with the package of the input file.

  • -imports: A list of explicit imports that should be used in the resulting source code, specified as a comma-separated list of elements of the form foo=bar/baz, where bar/baz is the package being imported and foo is the identifier to use for the package in the generated source code.

  • -aux_files: A list of additional files that should be consulted to resolve e.g. embedded interfaces defined in a different file. This is specified as a comma-separated list of elements of the form foo=bar/baz.go, where bar/baz.go is the source file and foo is the package name of that file used by the -source file.

  • -build_flags: (reflect mode only) Flags passed verbatim to go build.

  • -mock_names: A list of custom names for generated mocks. This is specified as a comma-separated list of elements of the form Repository=MockSensorRepository,Endpoint=MockSensorEndpoint, where Repository is the interface name and MockSensorRepository is the desired mock name (mock factory method and mock recorder will be named after the mock). If one of the interfaces has no custom name specified, then default naming convention will be used.

  • -self_package: The full package import path for the generated code. The purpose of this flag is to prevent import cycles in the generated code by trying to include its own package. This can happen if the mock's package is set to one of its inputs (usually the main one) and the output is stdio so mockgen cannot detect the final output package. Setting this flag will then tell mockgen which import to exclude.

  • -copyright_file: Copyright file used to add copyright header to the resulting source code.

  • -debug_parser: Print out parser results only.

  • -exec_only: (reflect mode) If set, execute this reflection program.

  • -prog_only: (reflect mode) Only generate the reflection program; write it to stdout and exit.

  • -write_package_comment: Writes package documentation comment (godoc) if true. (default true)

For an example of the use of mockgen, see the sample/ directory. In simple cases, you will need only the -source flag.

Building Mocks

type Foo interface {
  Bar(x int) int
}

func SUT(f Foo) {
 // ...
}
func TestFoo(t *testing.T) {
  ctrl := gomock.NewController(t)

  // Assert that Bar() is invoked.
  defer ctrl.Finish()

  m := NewMockFoo(ctrl)

  // Asserts that the first and only call to Bar() is passed 99.
  // Anything else will fail.
  m.
    EXPECT().
    Bar(gomock.Eq(99)).
    Return(101)

  SUT(m)
}

If you are using a Go version of 1.14+, a mockgen version of 1.5.0+, and are passing a *testing.T into gomock.NewController(t) you no longer need to call ctrl.Finish() explicitly. It will be called for you automatically from a self registered Cleanup function.

Building Stubs

type Foo interface {
  Bar(x int) int
}

func SUT(f Foo) {
 // ...
}
func TestFoo(t *testing.T) {
  ctrl := gomock.NewController(t)
  defer ctrl.Finish()

  m := NewMockFoo(ctrl)

  // Does not make any assertions. Executes the anonymous functions and returns
  // its result when Bar is invoked with 99.
  m.
    EXPECT().
    Bar(gomock.Eq(99)).
    DoAndReturn(func(_ int) int {
      time.Sleep(1*time.Second)
      return 101
    }).
    AnyTimes()

  // Does not make any assertions. Returns 103 when Bar is invoked with 101.
  m.
    EXPECT().
    Bar(gomock.Eq(101)).
    Return(103).
    AnyTimes()

  SUT(m)
}

Modifying Failure Messages

When a matcher reports a failure, it prints the received (Got) vs the expected (Want) value.

Got: [3]
Want: is equal to 2
Expected call at user_test.go:33 doesn't match the argument at index 1.
Got: [0 1 1 2 3]
Want: is equal to 1

Modifying Want

The Want value comes from the matcher's String() method. If the matcher's default output doesn't meet your needs, then it can be modified as follows:

gomock.WantFormatter(
  gomock.StringerFunc(func() string { return "is equal to fifteen" }),
  gomock.Eq(15),
)

This modifies the gomock.Eq(15) matcher's output for Want: from is equal to 15 to is equal to fifteen.

Modifying Got

The Got value comes from the object's String() method if it is available. In some cases the output of an object is difficult to read (e.g., []byte) and it would be helpful for the test to print it differently. The following modifies how the Got value is formatted:

gomock.GotFormatterAdapter(
  gomock.GotFormatterFunc(func(i interface{}) string {
    // Leading 0s
    return fmt.Sprintf("%02d", i)
  }),
  gomock.Eq(15),
)

If the received value is 3, then it will be printed as 03.

Debugging Errors

reflect vendoring error

cannot find package "."
... github.com/golang/mock/mockgen/model

If you come across this error while using reflect mode and vendoring dependencies there are three workarounds you can choose from:

  1. Use source mode.
  2. Include an empty import import _ "github.com/golang/mock/mockgen/model".
  3. Add --build_flags=--mod=mod to your mockgen command.

This error is due to changes in default behavior of the go command in more recent versions. More details can be found in #494.

mock's People

Contributors

aaronbee avatar abbot avatar awreece avatar balshetzer avatar codyoss avatar cvgw avatar daviddrysdale avatar dsymonds avatar fische avatar gliptak avatar hatstand avatar jacobsa avatar jeking3 avatar kishaningithub avatar korya avatar linzhp avatar lovung avatar mariusstaicu avatar marten-seemann avatar minicuts avatar msabramo avatar pasztorpisti avatar poy avatar rgarcia avatar sanposhiho avatar skudriashev avatar snarfed avatar sryoya avatar wencan avatar xmik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mock's Issues

running tests with gomock

when I try running tests with gomock vendored I get

./logic_test.go:17: cannot use mockCtrl (type *"github.com/golang/mock/gomock".Controller) as type *"github.com/foo/bar/vendor/github.com/golang/mock/gomock".Controller in argument to mock_db.NewMockDB

I'm running go version

go version go1.8 darwin/amd64

What I have done
I have updated the gomock repo
I have reinstalled mockgen
I have regenerated mocks

What fixes it
I have deleted the vendor gomock and it seems to work

reflect mode failed while model.InterfaceFromInterfaceType print to os.stdout

I run the following command :mockgen matching BannedDA
since it used reflect mode, it generate reflectProgram witch write the pkg to os.stdout, and then the mockgen try to read the resuld and decode it.

since I have init() method that print to std (using logrus logger) in part of my files, the stdout is not clean, and therefor the pkg can't be decoded in the following line, and the mockgen failed

I try to debug, and found that is {"BannedDA", reflect.TypeOf((*pkg_.BannedDA)(nil)).Elem()} cause the init() call.

The point is the we can't trust stdout, and assume that it contains only the encode pkg,

documentation needs a concrete "mockgen -import" example

I have a interface with an embedded http.ResponseWriter interface. However mockgen fails and there is no concrete example how how to solve this. I believe I'm supposed to use the -imports flag but without a concrete example it is proving difficult to track down. I debugged the mockgen code trying to track this down but ran out of time. A concrete example of this in the documentation would at least show me that it is not the right direction. Apologies if this should be attached to a subdirectory.

Can't mock internal interfaces

I get the following:

$ mockgen -self_package users -package users -destination ./cmd/api/internal/users/mocks_users_test.go github.com/foobar/api/cmd/api/internal/users Client
package main
    imports github.com/foobar/api/cmd/api/internal/users: use of internal package not allowed
2016/03/23 13:51:08 Loading input failed: exit status 1

Can't use mocks when recieved input has random fields.

you can't use EXPECT() for functions that recieve a complex object with random values. Other then that, objects that hold fields that are irellevant for the matching can't be matched with the given matchers. (I hope you don't mind the exessive tautology :))

In order to solve this, an additional matcher can be implemented. I thought to implement a StrMatcher, that will match between the objects String(). This way, if you want to ignore some of the fields in the matching process, you can implement a String() function that returns a description of all the object's interesing fields.

wildcard support

now we have lot's of interfaces and our comand look like:

//go:generate mockgen -package mocks -destination destpath.go package_name Interface1,Interface2,Interface3,Interface4,Interface5,Interface6,Interface7,Interface8,Interface9,Interface10,Interface11,Interface12,Interface12

Can we change it to

//go:generate mockgen -package mocks -destination destpath.go package_name "*"

?

SetArg on slice silently fails

When SetArg is used to set a slice argument, it silently fails to set the argument when the call occurs. This is because setting a slice by reflection cannot be done with a one-shot Set() call.

The diff below adds in support for setting of slices. A similar method will probably be needed for setting arrays, maps, and possible other types (maybe structs?), though my project doesn't have a need for these, so I didn't investigate their implementation.

--- github.com/golang/mock/gomock/call.go   2016-03-09 12:34:55.000000000 -0600
+++ github.com/golang/mock/gomock/call.go   2016-03-09 12:34:56.000000000 -0600
@@ -39,6 +39,13 @@
@@ -212,9 +233,38 @@
        }
        action = func() { c.doFunc.Call(doArgs) }
    }

    for n, v := range c.setArgs {
-       reflect.ValueOf(args[n]).Elem().Set(v)
-   }
+       switch reflect.TypeOf(args[n]).Kind() {
+       case reflect.Slice:
+           setSlice(args[n], v)
+       default:
+           reflect.ValueOf(args[n]).Elem().Set(v)
+       }
+   }

    rets = c.rets
    if rets == nil {
@@ -229,6 +279,15 @@
    return
 }

+func setSlice(arg interface{}, v reflect.Value) {
+   arg = reflect.MakeSlice(v.Type(), v.Len(), v.Cap())
+   av := reflect.ValueOf(arg)
+   for i := 0; i < av.Len(); i++ {
+       av.Index(i).Set(v.Index(i))
+   }
+}
+
 func (c *Call) methodType() reflect.Type {
    recv := reflect.ValueOf(c.receiver)
    for i := 0; i < recv.Type().NumMethod(); i++ {

Add Github-compliant generated comment to top of generated files

Currently MockGen produces this comment at the top of every generated file:

// Automatically generated by MockGen. DO NOT EDIT!

This is good and well, but these diffs don't get collapsed in Github reviews.

Changing this comment to the following would result in collapsed diffs:

// Code generated by MockGen. DO NOT EDIT!

For example, a user would see several of these:

screen shot 2016-08-25 at 11 04 58 am

Instead of a wall of text that doesn't need reviewing.

Setting mocked function's argument value

I am trying to mock out a GroupCache(source at https://github.com/golang/groupcache) instance for testing and I am running into issues with the Get() call. GroupCache's Get function returns an error object but places the result of the Get into the third argument, dest, which is of type groupcache.Sink. Is there a way to mock a mutation of an argument in a function using gomock? I have tried using both Do and SetArg but I have been unable to produce the result I am looking for. This is a simplified example of what I am trying to do:

type GroupCache interface {
    Get(ctx groupcache.Context, key string, dest groupcache.Sink) error
}
...

func TestGroupCacheMock(t *testing.T){
    ctrl := gomock.NewController(t)
    mockGroupCache := NewMockGroupCache(ctrl)

    mockGroupCache.EXPECT().Get(gomock.Any()).Return(nil).AnyTimes() // This line is where I am unsure of what to do.
    ...
}

So in this example I want the mocked call to Get from my mocked GroupCache to return nil and set the dest variable to some arbitrary value.

Thanks!

cannot set package name with -import

I'm having a problem with the -import mechanism in mockgen. I'm trying to set the name of a package which the mock is importing. I can't figure out how to do it.

When I create a mock with mockgen, it contains this import:

person "github.com/goblimey/films/models/person"

and the mock contains a method with a syntax error:

func (_m *MockDAO) Create(person person.Person) (person.Person, error) {
ret := _m.ctrl.Call(_m, "Create", person)
ret0, _ := ret[0].(person.Person) // syntax error here
ret1, _ := ret[1].(error)
return ret0, ret1
}

The syntax error is

./MockDAO.go:76: person.Person undefined (type person.Person has no field or method Person)

This is caused by confusion between the variable person and the package person. I need the import line to be something like:

import (
personModel "github.com/goblimey/films/models/person"

So the import is called personModel, not person.

It looks as if I can fix this problem using -import when I run mockgen. However, when I do that, I still get the import line that provokes the error. In this example, I run the command and display the first ten lines that it produces:

$ mockgen -package mocks -source ../daos/people/DAO.go
-imports 'personModel=github.com/goblimey/films/models/person' | head -10
// Automatically generated by MockGen. DO NOT EDIT!
// Source: ../daos/people/DAO.go

package mocks

import (
person "github.com/goblimey/films/models/person"
dbsession "github.com/goblimey/films/utilities/dbsession"
gomock "github.com/golang/mock/gomock"
)

mockgen needs a test suite

mockgen is currently being tested in an ad-hoc way. It needs a full and automated test suite to prevent breakages.

gomock fails with unexported interface methods in go 1.7

When working with unexported interface methods, even within the same package, errors are thrown in Go 1.7.

//bugreport.go
package bugreport

import "fmt"

// Example is an interface with a non exported method
type Example interface {
        someMethod(string) string
}

// CallExample is a simple function that uses the interface
func CallExample(e Example) {
        fmt.Println(e.someMethod("test"))
}
mockgen -destination  bugreport_mock_test.go -package bugreport -source=bugreport.go Example
//bugreport_test.go
package bugreport

import (
        "testing"

        "github.com/golang/mock/gomock"
)

func TestCallExample(t *testing.T) {
        ctrl := gomock.NewController(t)
        defer ctrl.Finish()

        e := NewMockExample(ctrl)
        e.EXPECT().someMethod(gomock.Any()).Return("it works!")

        CallExample(e)
}
go test                                                                                                                                                                                                                                                                                                                                                        !24218
--- FAIL: TestCallExample (0.00s)
panic: gomock: failed finding method someMethod on *bugreport.MockExample [recovered]
        panic: gomock: failed finding method someMethod on *bugreport.MockExample [recovered]
        panic: gomock: failed finding method someMethod on *bugreport.MockExample

The same test with someMethod written as SomeMethod works fine and as expected. This same test also works in Go 1.6.

Running function lambda arguments

Currently in our project, we have a function in our interface that accepts a lambda, does some logic (specifically, starts a database transaction), then runs the lambda in the context of that logic.

However, gomock doesn't have a way, as far as I've found, to run that lambda argument and then assert its behavior. I've hacked it a bit by replacing that function in the generated file with a simple command to run the argument in question and return its result, but it'd be nice if there was a built in way to do this without editing generated code.

I noticed that the Call type has a Do method which accepts a lambda (with a TODO to actually make sure it's a lambda), then calls it later down the line. Perhaps have a method on Call that, similar to SetArg, runs a particular argument in the same fashion Do does (example, CallArg(n int)). This would let me assert behavior that happens in that lambda (which also utilizes the mock). May be complicated by the fact that the lambda in question (in my code) needs to have the mock _m provided as an argument to it. Maybe CallArg(n int, args ...interface{}) to provide arguments for the call (which I could then feed the mock object to)?

Trimmed down example:

// persist.go
type Persister interface {
    RunInTx(TxFunc) error
    Foo()
    Bar()
}

type TxFunc func(tx Persister) error

func (p persister) RunInTx(f TxFunc) error {
    tx := p.StartTx()
    return f(tx)
}

// main.go
func main() {
    p := persist.NewPersister()
    log.Printf(DoStuff(p))
}

func DoStuff(p persist.Persister) error {
    return p.RunInTx(func(tx persist.Persister) error {
        tx.Foo()
        tx.Bar()
    })
}

// main_test.go
func TestDoStuff(t *testing.T) {
    mockCtrl := gomock.NewController(t)
    mockPersist := mock_persist.NewPersist(mockCtrl)

    // Currently these calls never happen, because the lambda in DoStuff is never run
    mockPersist.EXPECT().Foo()
    mockPersist.EXPECT().Bar()

    DoStuff(mockPersist)
}

And the hacky way I've solved it for now, for reference:

func (_m *MockPersister) RunInTx(_param0 persist.TxFunc) error {
    return _param0(_m)
    //ret := _m.ctrl.Call(_m, "RunInTx", _param0)
    //ret0, _ := ret[0].(error)
    //return ret0
}

Suggestion: add a var declaration to document the matched interface

I have a suggestion that the generated mock implementation code could include a var that illustrates the implemented interface.

This has become moderately widespread idiomatic practice, mostly for the purpose of documenting a type that matches an interface. Because Go doesn't include explicit syntax matching types to interfaces (and it doesn't need to, which is a good thing), this idiomatic practice has emerged instead.

An example is most useful here. Suppose I want to mock net/http/ResponseWriter. Using mockgen, I get

// Mock of ResponseWriter interface
type MockResponseWriter struct {
    ctrl     *gomock.Controller
    recorder *_MockResponseWriterRecorder
}

My suggestion is that mockgen should also generate this:

var _ *http.ResponseWriter = &MockResponseWriter{}

it would be clear to anyone reading the code that there is an implied 'implements' relationship between the type MockResponseWriter and the interface ResponseWriter. We know this because the compiler type-checks the var declaration in a way that guarantees it to be true (given that the compiler is successful). The var introduces an unnamed variable that is never used; presumably the compiler can notice that it's unused and eliminate it from the binary code.

flags for reflect

Would it be okay if I put up a PR to add the ability to use flags from the source generation to the reflect case? More accurately, adding some kind of -reflectOver and -interfaces flags.

This would let folks override the package name the reflect generation makes without having to do sed work.

For instance, we have linting tools that complain about underscores in package names but the interfaces I need are in another package and it would be convenient to refer to those interfaces by package and not source file. I've already got a really long sed in our go:generate to correct the import prefix of gomock in the generated file and another one would be unfortunate.

Mock import contains "vendor" directory.

I'm generating mocks using go generate command:
//go:generate mockgen -destination=../../stripe/mock.go -package=stripe bitbucket.org/____/go-lib/model/payment Client

In resulting file imports are:

import (
    payment "bitbucket.org/____/go-lib/model/payment"
    stripe_go "bitbucket.org/____/vendor/github.com/stripe/stripe-go"
    gomock "github.com/golang/mock/gomock"
)

Problematic one is stripe_go which should be github.com/stripe/stripe-go

I tried to add '-imports=stripe_go=github.com/stripe/stripe-go' and '-imports stripe_go=github.com/stripe/stripe-go' but it didn't helped.

Tag releases?

Hi @balshetzer - thanks for maintaining a great mocking package. We use it extensively internally and appreciate all your hard work!

The recently-committed #89 is backward-incompatible, and breaks a large number of our mocks (across many packages and repositories). It's certainly your prerogative to make backward-breaking changes like this, but it's hard on consumers of this package - particularly because there aren't any semver-tagged releases.

Would you consider tagging a 1.0.0 release? There's nothing stopping you from making backward-breaking changes afterwards and tagging a 2.0, but this way consumers can more easily control when they pull in breaking changes. It'll also make this package work better with tools like glide and dep.

Allow generating loose/dynamic mocks

Multiple mocking framework support both loose/dynamic and strict mocks*.
I propose adding support for generting such mocks as part of the mock generation api

loose := mocks.NewMyDynamicMock(ctrl)
strict := mocks.NewMyMock(ctrl)

or

strict := mocks.NewMyMock(ctrl)
loose := strict.Dynamic = true

Both solution are backward compatible.
I would like to hear your feedback about the idea.

**loose/dynamic - mock that doesn't panic when unregistered method is called

mock does not import the source file

I'm trying to generate a mock from a source.

$ cat x.go
package test

type X struct{}

type S interface {
	F(X)
}
$ mockgen -source x.go
// Automatically generated by MockGen. DO NOT EDIT!
// Source: x.go

package mock_test

import (
	gomock "github.com/golang/mock/gomock"
)

// Mock of S interface
type MockS struct {
	ctrl     *gomock.Controller
	recorder *_MockSRecorder
}

// Recorder for MockS (not exported)
type _MockSRecorder struct {
	mock *MockS
}

func NewMockS(ctrl *gomock.Controller) *MockS {
	mock := &MockS{ctrl: ctrl}
	mock.recorder = &_MockSRecorder{mock}
	return mock
}

func (_m *MockS) EXPECT() *_MockSRecorder {
	return _m.recorder
}

func (_m *MockS) F(_param0 X) {
	_m.ctrl.Call(_m, "F", _param0)
}

func (_mr *_MockSRecorder) F(arg0 interface{}) *gomock.Call {
	return _mr.mock.ctrl.RecordCall(_mr.mock, "F", arg0)
}

The generated mock does not import the original source for the type X.
Should I edit the generated mock? I tried some flags like -imports, but it didn't work.

Thanks,

calling Recorder methods with numbers causes misses due to Go's untyped constant rules

With an interface

type Adder interface{
   Inc(x int64) error
 }

the code generated for the MockAdder has the correct int type:

 func (_m *MockAdder) Do(_param0 int64) error {

while the Recorder has interface{}s for the argument:

func (_m *MockAdderRecoder) Do(arg0 interface{}) error {

This, unfortunately, causes spurious missed expectation in the test case below. This is because the "2" is handed to the AdderRecorder as an int. This is Go's untyped int handling code choosing int instead of int64 as its default type since none is provided explicitly.

It looks plausible from the code to generate the Recorder methods with the right argument types and convert them down as the call method one does. (But maybe I haven't seen the bug that prevented that in the first place.)

One workaround is to just use the same variable in both places and another is to explicitly convert it to the right type, but it might nice for small tests to just make the right type.

type Thing struct { a Adder }
func (t Thing) CallsAdderInc(x int64) { t.a.Inc(x) }

func TestAdder(t *testing.T) {
    ctrl := gomock.NewController(t)
    defer ctrl.Finish()
    adder := NewMockAdder(ctrl)
    myThing := Thing{adder}
    adder.EXPECT().Inc(2).Return(nil) // This 2 is turned into int instead of int64
    myThing.CallsAdderInc(2)
}

Mockgen emits bad code on empty interface (imported and not used: "reflect")

When running against an empty interface, mockgen is writing out Go files that import the reflect library but don't actually use it causing an unexpected error during test execution:

imported and not used: "reflect"

A rough example input file is:

package tmp

//go:generate mockgen -pkg mocks -destination=../mockgen_tmp.go PACKAGE/tmp EmptyInterfacer

type EmptyInterfacer interface {
	// TODO
}

And all matching instances of reflect in the generated file:

mocks$ grep -C2 reflect mockgen_tmp.go
import (
	gomock "github.com/golang/mock/gomock"
	reflect "reflect"
)

mocks$ 

Adding any placeholder method to this interface makes the error go away.

And thanks for your work on this. It's a nice tool ^_^

Tag a semver-compatible release

Is it possible for this project to tag a semver-compatible release? Most of the Go community, including the dep tool, is moving to this standard.

Without tagged releases, it's difficult for dependency management tools to work with this project.

STUBS method

Ok, now that we've got the *Times thing out of the way, the other thing I really miss is a STUBS method. I'd like to discuss this first with you before I go and try to contribute it, maybe cut down on the back-and-forth a bit.

When I've used other mocking frameworks, I use

  • A "STUBS" method to indicate "This test does not care that this method is called, it is simply here to allow the code under test to run"
  • A "EXPECTS" method to indicate "This is the expectation that this test cares about"

Would you be open to that addition?

Cannot install and run mockgen from the vendor directory

We would like to "vendorize" mockgen in our project, in order to freeze the version we are using and prevent unexpected breakages. We already do this with gomock for the same reason. We use govendor for this.

We vendorize gomock with govendor fetch github.com/golang/mock/[email protected]. Then, we can install mockgen from the vendor/ directory using govendor install +vendor. However, when we try to run mockgen, we get the following output:

prog.go:11:2: cannot find package "github.com/golang/mock/mockgen/model" in any of:
        /usr/local/Cellar/go/1.8.3/libexec/src/github.com/golang/mock/mockgen/model (from $GOROOT)
        /<omitted>/go/src/github.com/golang/mock/mockgen/model (from $GOPATH)

This is obviously because the package github.com/golang/mock/mockgen/model is not at the mentioned locations, but under our vendor/ directory. One way to fix this is to run go get -u github.com/golang/mock/mockgen, which places the model package under $GOPATH. Another way is to run govendor get -u github.com/golang/mock/[email protected], which is what we currently do. The advantage to "vendorizing" it as described above is that it centralizes the version management with the rest of our dependencies.

Why is there a runtime dependency on this model package? Shouldn't it be compiled into the mockgen binary? Is there any way to install mockgen from the vendor directory?

Adding line number of caller

Our team is really enjoying the mock support. Is there a way to get the controller to print the caller class and line number...

For example

--- FAIL: TestGetMany (0.00s)
    controller.go:113: no matching expected call: *lcp_mock.MockOrdersInterface.GetMany([context.Background wpID userID lpID confirmationNumber [statuses] [orderTypes]])
    controller.go:158: missing call(s) to *ids_mock.MockContextService.GetAccessToken(is anything, is anything, is anything)
    controller.go:158: missing call(s) to *lcp_mock.MockOrdersInterface.GetMany(is anything, is equal to accessToken, is equal to userID, is equal to lpID, is equal to confirmationNumber, is equal to [statuses], is equal to [orderTypes])
    controller.go:165: aborting test due to missing call(s)

Instead of controller.go:113 or 158, could the name of the function caller be included in the error message? This would help identify where in the code is actually trying to use the mock.

Thanks for this great library!

Methods containing type literals can't be mocked in source mode

If an interface has a method containing a literal struct type, then mockgen isn't able to generate a mock when using source mode.

E.g. interfaces.go:

type Foo interface {
    Baz(struct{})
}

type Bar interface {
    Baz() struct{}
}

$ mockgen -source=interfaces.go gives the following error: 2015/08/18 15:02:43 Loading input failed: interfaces.go:6:5: failed parsing arguments: don't know how to parse type *ast.StructType.

The mocks can be generated successfully when using mockgen in reflect mode.

Support variadic methods

I have a method with a printf-like signature: func(string, ...interface{}). When this is mocked and set up with myMock.EXPECT().myFunc(gomock.Any()), then the function is actually called, Call.call panics because len(args) < ft.NumIn(). This is because the generated mock code builds args by flattening the variadic arguments and normal arguments into a single slice, but the reflection API expects the variadic arguments to be wrapped up in a slice.

Controller needs to be initialized inside subtests

When we use mock with subtests, we need to initialize controller inside subtests.
If we initialize it outside of subtests and mock is not called expected, it outputs useless error which is panic: test executed panic(nil) or runtime.Goexit

good test

func TestSomething(t *testing.T) {
    t.Run("good", func(t *testing.T) {
        mockCtrl := gomock.NewController(t)
        defer mockCtrl.Finish()

        // test something
    })
}

bad test

func TestSomething(t *testing.T) {
    mockCtrl := gomock.NewController(t)
    defer mockCtrl.Finish()

    t.Run("bad", func(t *testing.T) {
        // test something
    })
}

I think this should be documented.

mocking dependencies located in a vendor directory

If you vendor a dependency into vendor/, what's the best way to generate mocks for it?

If you use mockgen to generate mocks for that specific version of it, e.g. mockgen a/vendor/somedependency, the generated mock has the wrong import: import somedependency "a/vendor/somedependency".

The workaround I'm currently using is making sure the version in $GOPATH/src/a/vendor/somedependency matches the version in $GOPATH/src/somedependency, and then running mockgen somedependency generates the correct code. This is cumbersome!

return value depend on input value

Is there way do return value depend on the input?
I want to do something like the following pseudo-code
var response string mock.EXPECT().SomeMethod(gomock.Any()).AnyTimes().Do(func(input string) { response = input + input }).Return(response)

I got deep into the code, and it look like it unsupported, I there other way to do it?

Unknown parameters mock call

Hi there,

Is there a way to expect a call without giving precisely the expected parameters and get them afterwards ?

Is pseudo code I'd like to do something like this

c := m.EXPECT(/* any */).Method()
MyTestedFunc()
s := C.Args[0].(string)
if strings.Contain(s, "test") { 
  // ...

Thanks a lot

Source mode fails with embedded interfaces in a specific case

Here are my test files (2 packages):

github.com/anyuser/pkg1/pkg1.go:

package pkg1

type I interface {
	E
}

type E interface {
	M()
}

github.com/anyuser/pkg2/pkg2.go:

//go:generate mockgen -source pkg2.go -destination pkg2_mock.go -package pkg2 -aux_files pkg1=../pkg1/pkg1.go
package pkg2

import "github.com/pasztorpisti/pkg1"

type I interface {
	pkg1.I
}

If you run go generate on pkg2 then you get the following error message:

2017/06/27 18:03:01 Loading input failed: ../pkg1/pkg1.go:4:2: unknown embedded interface E
pkg2.go:1: running "mockgen": exit status 1

Note that mock generation succeeds if you go to pkg1 and embed the E interface into I by prefixing it with the package name pkg1.E but that turns pkg1.go into invalid go code that doesn't compile.

Mockgen imports not working

mockgen with Imports flag does not generate the mocked file correctly.

mockgen -source ../iam/types/apis.go -destination cmd/iam_mock.go -package iam -imports iamTypes=git.nexgen.neustar.biz/IAS/iam/types

// Automatically generated by MockGen. DO NOT EDIT!
// Source: ../iam/types/apis.go

package iam

import (
gomock "github.com/golang/mock/gomock"
)

// Mock of UserApi interface
type MockUserApi struct {
ctrl *gomock.Controller
recorder *_MockUserApiRecorder
}

// Recorder for MockUserApi (not exported)
type _MockUserApiRecorder struct {
mock *MockUserApi
}

func NewMockUserApi(ctrl *gomock.Controller) *MockUserApi {
mock := &MockUserApi{ctrl: ctrl}
mock.recorder = &_MockUserApiRecorder{mock}
return mock
}

func (_m *MockUserApi) EXPECT() *_MockUserApiRecorder {
return _m.recorder
}

func (_m *MockUserApi) CreateUser(user IAMUser) (IAMUser, error) {
ret := _m.ctrl.Call(_m, "CreateUser", user)
ret0, _ := ret[0].(IAMUser)
ret1, _ := ret[1].(error)
return ret0, ret1
}

func (_mr *_MockUserApiRecorder) CreateUser(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "CreateUser", arg0)
}

// Mock of OrganizationApi interface
type MockOrganizationApi struct {
ctrl *gomock.Controller
recorder *_MockOrganizationApiRecorder
}

// Recorder for MockOrganizationApi (not exported)
type _MockOrganizationApiRecorder struct {
mock *MockOrganizationApi
}

func NewMockOrganizationApi(ctrl *gomock.Controller) *MockOrganizationApi {
mock := &MockOrganizationApi{ctrl: ctrl}
mock.recorder = &_MockOrganizationApiRecorder{mock}
return mock
}

func (_m *MockOrganizationApi) EXPECT() *_MockOrganizationApiRecorder {
return _m.recorder
}

func (_m *MockOrganizationApi) CreateOrganization(org IAMOrganization) (IAMOrganization, error) {
ret := _m.ctrl.Call(_m, "CreateOrganization", org)
ret0, _ := ret[0].(IAMOrganization)
ret1, _ := ret[1].(error)
return ret0, ret1
}

func (_mr *_MockOrganizationApiRecorder) CreateOrganization(arg0 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "CreateOrganization", arg0)
}

`go generate` fails after PR #78

Suddenly my build got broken. go generate started to fail with the following error message:

can't load package: package -o: cannot find package "-o" in any of:
	/usr/lib/go/src/-o (from $GOROOT)
	/godev/src/-o (from $GOPATH)
can't load package: package prog.bin: cannot find package "prog.bin" in any of:
	/usr/lib/go/src/prog.bin (from $GOROOT)
	/godev/src/prog.bin (from $GOPATH)
can't load package: package prog.go: cannot find package "prog.go" in any of:
	/usr/lib/go/src/prog.go (from $GOROOT)
	/godev/src/prog.go (from $GOPATH)

This is the failing go-generate line (it used to work fine):

//go:generate mockgen -package store -destination store-repo-mock_test.go github.com/PlanitarInc/walk-inside-api/service/userstore/repository Userstore

mockgen chokes on embedded interfaces

I was able to reduce my problem to this minimal case:

package test

import (
    "io"
)

type Iface interface {
    io.WriteCloser
}

Then mockgen fails:

$ $GOPATH/bin/mockgen -source iface.go -package test
2015/09/18 12:16:35 Loading input failed: iface.go:8:5: unknown embedded interface io.WriteCloser
$ $GOPATH/bin/mockgen -imports io=io -source iface.go -package test
2015/09/18 12:16:23 Loading input failed: iface.go:8:5: unknown embedded interface io.WriteCloser

Thanks for looking into the issue

Additional Matchers

A few additional generic matchers would be very useful, as they would eliminate most cases where custom single-use matchers are needed (at least for my uses cases).

I propose:

// Type creates a Matcher that matches values with the same dynamic type as x.
func Type(x interface{}) Matcher { ... }

// Length creates a Matcher that matches arrays, slices, strings, maps, and channels of length n.
func Length(n int) Matcher { ... }

// Field creates a Matcher that matches structs where the named field matches x.
func Field(fieldName string, x interface{}) Matcher { ... }

// AllOf creates a Matcher that matches values matching all supplied matchers.
// Each matcher is checked in the order provided. If a particular supplied matcher
// doesn't match, later matchers are not considered (i.e. early return on match failure).
func AllOf(matchers ...Matcher) Matcher { ... }

// Index matches arrays, slices, and strings where the i'th element matches x.
func Index(i int, x interface{}) Matcher { ... }

I can see two approaches to implementing these. The length matcher could either panic or just return false if an attempt is made to match against a value that is not an array, slice, map, string or channel. Similarly, the field matcher could either panic or just return false if an attempt is made to match against a value that isn't a struct, or a struct that doesn't have the named field. Again, the index matcher could either return false or just panic if an attempt is made to match against a value that isn't an array, slice, or string.

I think panicking is a better option, since attempting to match a value with an incompatible matcher (e.g. trying to match a slice with a field matcher) seems much more likely to be a bug in a test rather than a legitimate use-case for matching. Either way would be fine though.

I'm more than happy to provide a pull request with the implementation. I just wanted to get some feedback on the idea and whether you would be open to this change before I getting too carried away with implementing things.

Hard to debug when a Do(fn) function no longer matches its mock signature

Situation: we had code like:

type Foo interface {
  Bar(arg1, arg2 string)
  ...
}

and tests like:

do := func(arg1, arg2 string) { ... }
// ... bunch of code ...
myBarMock.EXPECT().Bar(wantArg1, wantArg2).Do(do)

Then we added an argument to Bar:

type Foo interface {
  Bar(arg1, arg2, arg3 string)
  ...
}

and updated the EXPECT():

do := func(arg1, arg2 string) { ... }
// ... bunch of code ...
myBarMock.EXPECT().Bar(wantArg1, wantArg2, wantArg3).Do(do)

... but forgot to update do. The result was "panic: reflect: Call with too many input arguments" with no strong indication that what was wrong was the do function, rather than some place where the third argument hadn't been added (e.g. missing wantArg3).
It would be nice if the message said something more obvious like "EXPECT.()Do() function doesn't match the mock signature".

Ignore method argument

In some use case, I don't want the mock matcher to check my arguments value

like google mock

using ::testing::_;
...
// Expects the turtle to move forward.
EXPECT_CALL(turtle, Forward(_));

difference between source and reflection based output

Just helped a friend who is newer to Go through getting a mock made.

She wanted it for tests in her current package and so used the "reflection" version of the mockgen command to make them. However, that caused a circular dependency error in her own build because her own package was being imported.

Using the -source variation, however, "fixed" the problem.

The -self_package flag fixes this for real, but we couldn't figure that out from the docs immediately.

The "fix" of using -source came to us first, but that was maybe an accident? If it was an accident, then this ticket is for figuring out if the reflection version can figure out that the destination file will be in the same package.

If it wasn't, then maybe I need to come up with a documentation PR.

Error - Mock method with int and string parameters

Mocking a method with int and string parameters generates a mock that does not expect those types. However, if both parameters are of type string, it works properly.

output
alem@alem-vm:~/Workspace/go/src/alem/test1$ go test lib_test.go                                                                                                         
--- FAIL: TestMyThing (0.00s)
        controller.go:113: no matching expected call: *mock_mypackage.MockMyInterface.SomeMethod([1 second])
        controller.go:158: missing call(s) to *mock_mypackage.MockMyInterface.SomeMethod(is equal to 1, is equal to second)
        controller.go:165: aborting test due to missing call(s)
FAIL
FAIL    command-line-arguments  0.002s
lib.go
package mypackage

type MyInterface interface {
  SomeMethod(x uint64, y string)
}
lib_test.go
package mypackage

import (
  "testing"
  "alem/test1/lib_mock"
  "github.com/golang/mock/gomock"
)

func TestMyThing(t *testing.T) {
  mockCtrl := gomock.NewController(t)
  defer mockCtrl.Finish()

  mockObj := mock_mypackage.NewMockMyInterface(mockCtrl)

  gomock.InOrder(
    mockObj.EXPECT().SomeMethod(1, "second"),
  )

  mockObj.SomeMethod(1, "second")
}
mockgen
mockgen -source=lib.go > lib_mock/lib_mock.go

Call.After doesn't check for adding a dependency on "self"

The func (c *Call) After(preReq *Call) *Call doesn't check/reject buggy invocations when c == preReq.

This is a minor problem. I ran into it accidentally by putting individual Call instances into variables and manually connecting them using After() and gomock.InOrder().

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.