golang / mock Goto Github PK
View Code? Open in Web Editor NEWGoMock is a mocking framework for the Go programming language.
License: Apache License 2.0
GoMock is a mocking framework for the Go programming language.
License: Apache License 2.0
Currently, if Finish()
is called and some expected calls did not occur, t.Fatal()
is called, aborting the test. However, in the cast of tabular tests, it would be preferable if only t.Error()
was called so that the other test cases could be run.
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!
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?
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)
}
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()
.
Add this link https://godoc.org/github.com/golang/mock/gomock to project description so it is easier to lookup docs.
mockgen is currently being tested in an ad-hoc way. It needs a full and automated test suite to prevent breakages.
Is it any possible to implement no code generation mock library? Just like PowerMock in Java.
After last day commits (Jul 22, 2017) we get this on mock generated file. reverting to dbe9dea and everything is fine.
I can provide more information if you need, currently searching.
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"
)
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.
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,
I have a mock object that has > 3 EXPECT()
calls on it. I would like to figure out what is being called and what returns what.
Is there a suggested way to do this?
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
Would you be open to that addition?
source code
type A struct {}
type I interface {
Foo() A
}
Mock that was generate from genmock will have error because when genmock create mock file mock package is mock_* so mock won't find struct A in mock_* package
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?
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
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(_));
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
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:
Instead of a wall of text that doesn't need reviewing.
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.
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.
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 ^_^
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.
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.
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
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,
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
}
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!
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)
}
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
We have a project which excludes some C dependencies by running go build as go build --tags "tag1 tag2 tag3". Running ginkgo with ginkgo --tags "tag1 tag2 tag3". However, we couldn't find such option with mockgen. Is there any way to achieve that with mockgen?
There's a very informative usage statement stored in usage()
, but it's not used when mockgen is invoked with no arguments:
$ mockgen
2017/04/13 11:01:21 Expected exactly two arguments
It would be nice if this printed the usage statement too.
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++ {
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.
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
package mypackage
type MyInterface interface {
SomeMethod(x uint64, y string)
}
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 -source=lib.go > lib_mock/lib_mock.go
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!
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.
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 "*"
?
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".
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.
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
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.
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
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.
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.
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.
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.
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
.
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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.