GithubHelp home page GithubHelp logo

mock's Introduction

gomock

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.

This project originates from Google's golang/mock repo. Unfortunately, Google no longer maintains this project, and given the heavy usage of gomock project within Uber, we've decided to fork and maintain this going forward at Uber.

Contributions are welcome in the form of GitHub issue or PR!

Supported Go Versions

go.uber.org/mock supports all Go versions supported by the official Go Release Policy. That is, the two most recent releases of Go.

Installation

Install the mockgen tool.

go install go.uber.org/mock/mockgen@latest

To ensure it was installed correctly, use:

mockgen -version

If that fails, make sure your GOPATH/bin is in your PATH. You can add it with:

export PATH=$PATH:$(go env GOPATH)/bin

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)

  • -write_generate_directive: Add //go:generate directive to regenerate the mock. (default false)

  • -write_source_comment: Writes original file (source mode) or interface names (reflect mode) comment if true. (default true)

  • -typed: Generate Type-safe 'Return', 'Do', 'DoAndReturn' function. (default false)

  • -exclude_interfaces: Comma-separated names of interfaces to be excluded

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)

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

Building Stubs

type Foo interface {
  Bar(x int) int
}

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

  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 any) string {
    // Leading 0s
    return fmt.Sprintf("%02d", i)
  }),
  gomock.Eq(15),
)

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

mock's People

Contributors

alexandear avatar balshetzer avatar codyoss avatar cvgw avatar damianopetrungaro avatar daviddrysdale avatar dependabot[bot] avatar dsymonds avatar fische avatar hatstand avatar jacobsa avatar korya avatar linzhp avatar lovung avatar mariusstaicu avatar marten-seemann avatar msabramo avatar nguyenfilip avatar pasztorpisti avatar poy avatar r-hang avatar sanposhiho avatar shogo82148 avatar sodul avatar sryoya avatar sywhang avatar tra4less avatar tulzke 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

mock's Issues

Split the Package comment from the "boilerplate" comments

Actual behavior A clear and concise description of what the bug is.
The package comments are generated like this:

//	mockgen -destination demo/mock.go -package demo . Demoer
//
// Package demo is a generated GoMock package.
package demo

However, this is not correct, as it doesn't follow the package guidelines documented here: https://staticcheck.io/docs/checks#ST1000

Expected behavior A clear and concise description of what you expected to
happen.

I expect the generated code to be:

//	mockgen -destination demo/mock.go -package demo . Demoer
//

// Package demo is a generated GoMock package.
package demo

This would follow the guidelines and make the linter happy too.

To Reproduce Steps to reproduce the behavior

  1. Run mockgen -destination demo/mock.go -package demo . Demoer on any interface/package
  2. Observe the results

Additional Information

  • gomock mode (reflect or source): source
  • gomock version or git ref: v0.3.1-0.20231011042131-892b665398ec
  • golang version: go version go1.21.3 linux/amd64
  • staticcheck version: v0.5.0-0.dev.0.20230826160118-ad5ca31ff221

Triage Notes for the Maintainers

Here's an attempt at fixing the issue: #112.

non-reproducible mocks due to recording of invocation arguments

Actual behavior

In quic-go, I'm using go run go.uber.org/mock/mockgen [...] to generate mocks (example). This is a common pattern, and it has the nice property that mock generation becomes independent from the locally install version of mockgen, and instead the version defined in go.mod is used (the project contains a tools.go file behind a build flag that pins the version).

I then have a job on CI that runs go generate ./... and checks that all generated files are consistent. This job has proved invaluable, considering the number of times it has prevented us from accidentally getting the repo into an inconsistent state.

Expected behavior

I expected this job to succeed when using the latest (unreleased) version. However, due to #31, the invocation arguments are now recorded in the mock file. This now contains the path of a temporary directory:

// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/quic-go/quic-go (interfaces: TokenStore)
//
// Generated by this command:
//
//	/var/folders/q0/b5ynf00142l7bl9sp8y098zr0000gn/T/go-build1159986194/b001/exe/mockgen -typed -package quic -self_package github.com/quic-go/quic-go -self_package github.com/quic-go/quic-go -destination mock_token_store_test.go github.com/quic-go/quic-go TokenStore

Obviously, this path differs between platforms and even between repeated invocations on the same machine. Generated mocks are effectively non-deterministic now.

I'm not sure I find #31 very useful to begin with, and in its current state this will cause quite a bit of pain in quic-go. We'd have to pipe the mockgen output through awk / grep to remove the additional lines introduced in #31.

I can see two ways to resolve this problem:

  1. Don't print the full path of the binary, i.e. just print mockgen instead of /var/folders/q0/b5ynf00142l7bl9sp8y098zr0000gn/T/go-build1159986194/b001/exe/mockgen.
  2. Hide this feature behind a config flag. No strong opinions regarding the default value of that flag.

Additional Information

  • gomock mode (reflect or source): both
  • gomock version or git ref: 837f20a
  • golang version: Go 1.21.1

Triage Notes for the Maintainers

Release schedule

Sorry to create an issue for this, but I wasn't sure where else to ask. Are there plans to cut a new release soon?

Thank you

Add matcher for structs with ignored order in nested fields

In PR golang/mock#546 we got a matcher that ignores the order of a slice or array. Sometimes the order can't be controlled properly it makes sense to have this matcher. But it is only capable of ignoring the order if the struct is of type slice or array, and not nested.

I would propose to add a matcher that will return true for unordered nested structs as well. Example unit test:

func TestOrderlessMatcher(t *testing.T) {
	testCases := []struct {
		expected interface{}
		value    interface{}
		matches  bool
	}{
		{
			struct{ List []string }{List: []string{"Value1", "Value2"}},
			struct{ List []string }{List: []string{"Value2", "Value1"}},
			true,
		},
	}
	for i, testCase := range testCases {
		t.Run(fmt.Sprintf("Test #%d", i), func(t *testing.T) {
			assert := assert.New(t)
			m := matchers.NewOrderlessMatcher(testCase.expected)
			assert.Equal(testCase.matches, m.Matches(testCase.value))
		})
	}
}

A matcher that matches at least one of the given matchers

Requested feature

A new matcher combinator like All but returns true when one of the matchers returns true.

Why the feature is needed

We currently have All that matches all the matchers, just like the universal quantifier in the logic. It would be great to have AnyOf that matches at least one of them, similar to the existential quantifier in the logic. This is helpful when an argument can be one of several values. For example, with the new AnyOf matcher, we may write the following:

gomock.InOrder(
	m.EXPECT().SetDirection(AnyOf("north", "south", "west", "east"), true),
	m.EXPECT().Run(),
)

This means we expect a method call SetDirection("north", true), SetDirection("south", true), SetDirection("west", true) or SetDirection("east", true), which is then followed by a method call Run().

(Optional) Proposed solution

Here is a sample implementation. It's trivial for me to make a PR if the maintainers feel positive about this feature.

type anyOfMatcher struct {
	matchers []Matcher
}

func (am anyOfMatcher) Matches(x any) bool {
	for _, m := range am.matchers {
		if m.Matches(x) {
			return true
		}
	}
	return false
}

func (am anyOfMatcher) String() string {
	ss := make([]string, 0, len(am.matchers))
	for _, matcher := range am.matchers {
		ss = append(ss, matcher.String())
	}
	return strings.Join(ss, " | ")
}

func AnyOf(xs ...any) Matcher {
	ms := make([]Matcher, 0, len(xs))
	for _, x := range xs {
		if m, ok := x.(Matcher); ok {
			ms = append(ms, m)
		} else {
			ms = append(ms, Eq(x))
		}
	}
	return anyOfMatcher{ms}
}

Related issues and PRs (from the original gomock)

`nil` value `TestReporter` in `NewController`

Is this allowed or not? It does not throw an error right away, but opens the door for NPEs in methods like (h *nopTestHelper) Errorf(. I understand it might be backwards incompat to start enforcing now, so it is a constraint we can relax, or at least document?

gomock_reflect_4282172408 directory remained not deleted after error

Actual behavior A clear and concise description of what the bug is.

I used to this kind of situation where go generate fails and the mockgen leftovers got not clean

Expected behavior A clear and concise description of what you expected to
happen.

mockgen should clean artifact files

To Reproduce Steps to reproduce the behavior

make gomock fail?

  1. ...
  2. ...

Additional Information

  • gomock mode (reflect or source): I assume it is in reflect mode go:generate mockgen -destination=foo.go -package=foo . Fooer
  • gomock version or git ref: mockgen --version: v0.2.0
  • golang version: go version go1.21.0 linux/amd64

Triage Notes for the Maintainers

Wrong print msg when comparing initialized and uninitialized slice

Actual behavior A clear and concise description of what the bug is.

=== RUN   TestA
    tests/A_test.go:15: Unexpected call to *tests.MockAer.Hello([[]]) at tests/A_test.go:15 because:
        expected call at tests/A_test.go:14 doesn't match the argument at index 0.
        Got: [] ([][32]uint8)
        Want: is equal to [] ([][32]uint8)

Expected behavior

=== RUN   TestA
    tests/A_test.go:15: Unexpected call to *tests.MockAer.Hello([[]]) at tests/A_test.go:15 because:
        expected call at tests/A_test.go:14 doesn't match the argument at index 0.
        Got: nil ([][32]uint8)
        Want: is equal to [] ([][32]uint8)

To Reproduce Steps to reproduce the behavior

Generate mocks for this interface

type Aer interface {
	Hello([][32]byte)
}

Then write this test

func TestA(t *testing.T) {
	ctrl := gomock.NewController(t)
	mockA := NewMockAer(ctrl)
	mockA.EXPECT().Hello([][32]byte{})
	mockA.Hello(nil)
}

You will reproduce the above error, which is very confusing. It's showing that Got and Want are the same, even though they actually aren't.

Additional Information

  • gomock mode (reflect or source): not sure what this means.
  • gomock version or git ref: go.uber.org/mock v0.2.0
  • golang version: go version go1.20.6 darwin/arm64

type-safe calls can't be used in gomock.InOrder

Actual behavior When using type-safe mode (-typed), the calls returned from EXPECT().Method() are typed. This is great, and a feature I've been waiting for for a long time. However, it makes it impossible to use them in gomock.InOrder, since InOrder expects a *gomock.Call.

Expected behavior I expected gomock.InOrder to work seamlessly.

To Reproduce Steps to reproduce the behavior

  1. Generate mocks using -typed
  2. Use gomock.InOrder with calls of that mock

Additional Information

  • gomock mode (reflect or source): reflect
  • gomock version or git ref: v0.2.0
  • golang version: Go 1.21

Triage Notes for the Maintainers

Failed CI run on quic-go after generating typed mocks: https://github.com/quic-go/quic-go/actions/runs/5988902088/job/16244553880?pr=4051 (PR: quic-go/quic-go#4051)

Broken unit tests on Windows

TestParsePackageImport_FallbackGoPath and TestParsePackageImport_FallbackMultiGoPath are not working:

?       go.uber.org/mock/gomock/internal/mock_gomock    [no test files]
ok      go.uber.org/mock/gomock 0.991s
?       go.uber.org/mock/mockgen/internal/tests/add_generate_directive  [no test files]
?       go.uber.org/mock/mockgen/internal/tests/aux_imports_embedded_interface/faux     [no test files]
?       go.uber.org/mock/mockgen/internal/tests/const_array_length      [no test files]
?       go.uber.org/mock/mockgen/internal/tests/copyright_file  [no test files]
?       go.uber.org/mock/mockgen/internal/tests/custom_package_name/client/v1   [no test files]
?       go.uber.org/mock/mockgen/internal/tests/custom_package_name/validator   [no test files]
?       go.uber.org/mock/mockgen/internal/tests/defined_import_local_name       [no test files]
--- FAIL: TestParsePackageImport_FallbackGoPath (0.00s)
    mockgen_test.go:385: expect example.com\foo, got example.com/foo
--- FAIL: TestParsePackageImport_FallbackMultiGoPath (0.02s)        
    mockgen_test.go:412: expect example.com\foo, got example.com/foo
FAIL
FAIL    go.uber.org/mock/mockgen        8.159s
ok      go.uber.org/mock/mockgen/internal/tests/aux_imports_embedded_interface  0.385s
ok      go.uber.org/mock/mockgen/internal/tests/custom_package_name/greeter     0.414s
?       go.uber.org/mock/mockgen/internal/tests/dot_imports     [no test files]
?       go.uber.org/mock/mockgen/internal/tests/empty_interface [no test files]
?       go.uber.org/mock/mockgen/internal/tests/empty_interface [no test files]
?       go.uber.org/mock/mockgen/internal/tests/exclude [no test files]
?       go.uber.org/mock/mockgen/internal/tests/extra_import    [no test files]
ok      go.uber.org/mock/mockgen/internal/tests/generated_identifier_conflict   0.779s
?       go.uber.org/mock/mockgen/internal/tests/import_embedded_interface/ersatz        [no test files]
?       go.uber.org/mock/mockgen/internal/tests/import_embedded_interface/faux  [no test files]
?       go.uber.org/mock/mockgen/internal/tests/import_embedded_interface/other/ersatz  [no test files]
?       go.uber.org/mock/mockgen/internal/tests/import_embedded_interface/other/log     [no test files]
ok      go.uber.org/mock/mockgen/internal/tests/import_embedded_interface       0.660s
?       go.uber.org/mock/mockgen/internal/tests/import_source   [no test files]
?       go.uber.org/mock/mockgen/internal/tests/import_source/definition        [no test files]
?       go.uber.org/mock/mockgen/internal/tests/internal_pkg    [no test files]
?       go.uber.org/mock/mockgen/internal/tests/internal_pkg/subdir/internal/pkg        [no test files]
?       go.uber.org/mock/mockgen/internal/tests/internal_pkg/subdir/internal/pkg/reflect_output [no test files]
?       go.uber.org/mock/mockgen/internal/tests/internal_pkg/subdir/internal/pkg/source_output  [no test files]
?       go.uber.org/mock/mockgen/internal/tests/missing_import/output   [no test files]
?       go.uber.org/mock/mockgen/internal/tests/missing_import/source   [no test files]
ok      go.uber.org/mock/mockgen/internal/tests/mock_in_test_package    0.681s [no tests to run]
ok      go.uber.org/mock/mockgen/internal/tests/overlapping_methods     0.583s
?       go.uber.org/mock/mockgen/internal/tests/parenthesized_parameter_type    [no test files]
?       go.uber.org/mock/mockgen/internal/tests/performance/big_interface       [no test files]
ok      go.uber.org/mock/mockgen/internal/tests/panicing_test   0.388s [no tests to run]
?       go.uber.org/mock/mockgen/internal/tests/self_package    [no test files]
ok      go.uber.org/mock/mockgen/internal/tests/test_package    0.384s [no tests to run]
ok      go.uber.org/mock/mockgen/internal/tests/typed_inorder   0.390s
ok      go.uber.org/mock/mockgen/internal/tests/unexported_method       0.469s
?       go.uber.org/mock/mockgen/internal/tests/vendor_dep      [no test files]
?       go.uber.org/mock/mockgen/internal/tests/vendor_dep/source_mock_package  [no test files]
?       go.uber.org/mock/mockgen/internal/tests/vendor_pkg      [no test files]
ok      go.uber.org/mock/mockgen/model  0.738s
ok      go.uber.org/mock/sample 0.695s
?       go.uber.org/mock/sample/concurrent/mock [no test files]
?       go.uber.org/mock/sample/imp1    [no test files]
?       go.uber.org/mock/sample/imp2    [no test files]
?       go.uber.org/mock/sample/imp3    [no test files]
?       go.uber.org/mock/sample/imp4    [no test files]
ok      go.uber.org/mock/sample/concurrent      0.469s
FAIL

Add a helper method for inline setup of mocks

Requested feature
A helper method that would make inline construction of mocks possible.

Why the feature is needed

So the test code would look nicer

Proposed solution

Maybe something like a SETUP method in every mock, which woul receive a function that configures the mock.

Example (before):

ctrl := gomock.NewController(t)
defer ctrl.Finish()

mockReader1 := NewMockDep1(ctrl)
mockReader1.EXPECT().
    ReadSomething(gomock.Any(), gomock.Any()).
    Return("first call", nil)
mockReader1.EXPECT().
    ReadSomething(gomock.Any(), gomock.Any()).
    Return("second call", nil)
mockReader1.EXPECT().
    ReadSomething(gomock.Any(), gomock.Any()).
    Return("third call", nil)

mockWriter := NewMockDep1(ctrl)
mockWriter.EXPECT().
    WriteSomething(gomock.Any(), gomock.Any()).
    Return("first call", nil)
mockWriter.EXPECT().
    WriteSomething(gomock.Any(), gomock.Any()).
    Return("second call", nil)
mockWriter.EXPECT().
    WriteSomething(gomock.Any(), gomock.Any()).
    Return("third call", nil)

sut := NewSystemUnderTest(mockReader, mockWriter)
sut.DoAction()

Example (after):

ctrl := gomock.NewController(t)
defer ctrl.Finish()

sut := NewSystemUnderTest(
    NewMockReader(ctrl).SETUP(func (mock *MockReader) {
        mock.EXPECT().
            ReadSomething(gomock.Any(), gomock.Any()).
            Return("first call", nil)
        mock.EXPECT().
            ReadSomething(gomock.Any(), gomock.Any()).
            Return("second call", nil)
        mock.EXPECT().
            ReadSomething(gomock.Any(), gomock.Any()).
            Return("third call", nil)
    }),
    NewMockWriter(ctrl).SETUP(func (mock *MockWriter) {
        mock.EXPECT().
            WriteSomething(gomock.Any(), gomock.Any()).
            Return("first call", nil)
        mock.EXPECT().
            WriteSomething(gomock.Any(), gomock.Any()).
            Return("second call", nil)
        mock.EXPECT().
            WriteSomething(gomock.Any(), gomock.Any()).
            Return("third call", nil)
    }),
)
sut.DoAction()

`go get go.uber.org/mock` failure

Actual behavior

โฏ go get go.uber.org/mock                                                                                                                                                                                                    (cp-us-west-2/fetchers)
go: unrecognized import path "go.uber.org/mock": reading https://go.uber.org/mock?go-get=1: 404 Not Found
        server response: 404 page not found

Expected behavior
Successful installation

Additional Information
go version go1.20.4 darwin/arm64

Add helpful info to README regarding GOPATH during installation

Requested feature

  • I'd like to add a helpful tidbit about ensuring GOPATH/bin is part of PATH, as this held me up for a bit when trying to use this tool.

Why the feature is needed

  • Will allow more users to start using the tool faster

(Optional) Proposed solution

  • I don't have push access, but adding a few lines after line 27 in the Installation section would suffice:

To ensure it was installed correctly, use:

mockgen -version

If not, make sure your GOPATH/bin is in your PATH. Otherwise add it with:

export PATH=$PATH:$(go env GOPATH)/bin

MGet with go redis failing

Actual behavior The unit test at https://github.com/PhilAndrew/mockgenredisv9/blob/main/mock_v9/redis_cache_v2_test.go#L36 should pass as it takes and supplies 3 parameters. Instead it says wrong number of arguments in DoAndReturn func for *mock_v9.MockCmdable.MGet: got 3, want 2. This suggests there is a bug in mockgen where it is not compatible with Redis v9 for the MGet method https://github.com/redis/go-redis
I tried modifying the number of parameters but that didn't work.

Expected behavior I expect the unit test at this github repo to pass. https://github.com/PhilAndrew/mockgenredisv9

To Reproduce Steps to reproduce the behavior

Git clone https://github.com/PhilAndrew/mockgenredisv9 and run go test -cover ./...

Additional Information

  • gomock mode (reflect or source):I generated source
  • gomock version or git ref:Latest version v0.3.0
  • golang version:1.20

Triage Notes for the Maintainers

Allow generation of the โ€œGenerated by this commandโ€ comment to be disabled

Requested feature
A way to disable generation of the โ€œGenerated by this commandโ€ comment.

Why the feature is needed
The comment has already been fixed to drop the path to mockgen, since that isnโ€™t necessarily consistent. The same applies to paths provided as arguments; see kubernetes/kubernetes#120969 for one such instance (the copyright_file arguments point to files in temporary directories).

(Optional) Proposed solution
I am about to submit a PR adding an option to take care of this by adding a command-line option to disable it.
Another possibility would be to remove paths from file names provided as arguments, perhaps only if they are absolte, but that may not be generally desirable.

Flag `-write_generate_directive` produces wrong paths in the directive

Actual behavior

Flag -write_generate_directive adds the go:generate directive, ignoring the future working directory. That leads to a failure of go generate.

Expected behavior

go:generate directive should be changed to respect that the current working directory will be different from the original execution.

To Reproduce

echo 'package pkg' > file.go
mockgen -write_generate_directive -source file.go -destination mocks/mock.go
grep 'go:generate' mocks/*
//go:generate mockgen -write_generate_directive -source file.go -destination mocks/mock.go
go generate ./...
2023/12/31 15:40:41 Loading input failed: failed parsing source file file.go: open file.go: no such file or directory
mocks/mock.go:12: running "mockgen": exit status 1

To fix

sed -i '' -e 's#-source file.go -destination mocks/mock.go#-source ../file.go -destination mock.go#' mocks/*
grep 'go:generate' mocks/*
//go:generate mockgen -write_generate_directive -source ../file.go -destination mock.go
go generate ./...

mock_names flag does not change naming of ...Call struct in typed mocks

Actual behavior
Using -mock_names option does not alter the name of ...Call structs.

e.g. mockgen -typed=true -mock_names=Writer=OtherWriter io Writer generates

// WriterWriteCall wrap *gomock.Call
type WriterWriteCall struct {
	*gomock.Call
}

This causes problems if using -mock_names to avoid clashes between mocks for interfaces with the same name (e.g. if I have my own Writer interface and also want to mock io.Writer in the same package) since there will be multiple structs with the same type name in the same package.

Expected behavior
I expect using -mock_names option to change the name of ...Call structs.

e.g. mockgen -typed=true -mock_names=Writer=OtherWriter io Writer generates

// OtherWriterWriteCall wrap *gomock.Call
type OtherWriterWriteCall struct {
	*gomock.Call
}

To Reproduce

Run mockgen -typed=true -mock_names=Writer=OtherWriter io Writer

Additional Information

  • gomock mode (reflect or source): both
  • gomock version or git ref: v0.3.0
  • golang version: 1.21.3

Triage Notes for the Maintainers

Unable to generate mock for package using alternate major version and generic type with reflect mode

Actual behavior

mockgen generates a uncompilable mock file for interface using alternate major version package and generic types.

Here is a reproduce:

package mockgenrepro

import (
	"context"
	"fmt"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
	armcontainerservice "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v4" // a package using alternate major version
)

//go:generate mockgen -destination mock_main/foo.go -package mock_main . Interface

type Interface interface {
	BeginAbortLatestOperation(ctx context.Context, resourceGroupName string, resourceName string, agentPoolName string, options *armcontainerservice.AgentPoolsClientBeginAbortLatestOperationOptions) (*runtime.Poller[armcontainerservice.AgentPoolsClientAbortLatestOperationResponse], error)
}

Above program fails the mockgen with error like this (full output):

2023/09/26 16:19:41 Failed to format generated source code: mock_main/foo.go:41:201: missing ',' in type argument list (and 1 more errors)

You can find the full repro here: https://github.com/bahe-msft/mockgen-repro

Expected behavior

Generated mock file should be a valid go source. Expected output: https://github.com/bahe-msft/mockgen-repro/blob/main/mock_main/foo.go

To Reproduce Steps to reproduce the behavior

  1. clone https://github.com/bahe-msft/mockgen-repro
  2. run go generate -v ...

Additional Information

  • gomock mode (reflect or source): reflect
  • gomock version or git ref: v0.3.0
  • golang version: go1.21.0

The same mock can be generated using source mode. But our project is using reflect mode heavily, so we want to fix in reflect mode as well.

Triage Notes for the Maintainers

Mock interface which has an un-exported method

Actual behavior
I'm not able to cast a mocked struct to the actual interface, if it has an un-exported method:

./main_test.go:19:64: cannot use mocks.NewMockTraceServiceServer(mockController) (value of type *mocks.MockTraceServiceServer) as "go.opentelemetry.io/proto/otlp/collector/trace/v1".TraceServiceServer value in variable declaration: *mocks.MockTraceServiceServer does not implement "go.opentelemetry.io/proto/otlp/collector/trace/v1".TraceServiceServer (missing method mustEmbedUnimplementedTraceServiceServer)
FAIL    github.com/miparnisari/mockGo [build failed]

Expected behavior
I'm able to cast a mocked struct to the actual interface, if it has an un-exported method, e.g.

type TraceServiceServer interface {
	Export(context.Context, *ExportTraceServiceRequest) (*ExportTraceServiceResponse, error)
	mustEmbedUnimplementedTraceServiceServer()
}

To Reproduce

  1. git clone [email protected]:miparnisari/mockGO.git
  2. go generate && go test .

Additional Information

  • gomock mode (reflect or source): reflect
  • gomock version or git ref: n/a
  • golang version: 1.20

Support generating mock for interfaces with generics

Hey team,

Hope you are doing well.
Stumbled upon on this issue. In code as well as on the archived repo.
To not copy paste too much, is this perhaps on the roadmap for you?

It seems that the previous team was on it, but didn't got to the latest release including it.

Embed original interface into Mock struct

Requested feature

I would like to have option to embed original interface into generated Go structure.

Why the feature is needed

If the interface has unexported methods, the generated mock cannot be used as it does not fulfill the original interface. Embedding it however solves the issue. As discussed here https://groups.google.com/g/golang-nuts/c/6hpUErAfMHI

(Optional) Proposed solution

Solution should be pretty easy, as @stoikheia created PR in old repo golang/mock#683

Code generated by mockgen on Windows should not be different

Code generated by mockgen on Windows machines has a different header comment from code generated on other platforms.

@@ -3,7 +3,7 @@
 //
 // Generated by this command:
 //
-//     mockgen -destination=mock_downloader.go -package downloader . Downloader
+//     mockgen.exe -destination=mock_downloader.go -package downloader . Downloader
 //
 // Package downloader is a generated GoMock package.
 package downloader

deadlock on unexpected call with mocked argument implementing `fmt.Stringer`

Actual behavior Deadlock on unexpected call to function where one or more arguments are a generated mock that implements fmt.Stringer.

Expected behavior No deadlock on an unexpected call

To Reproduce Steps to reproduce the behavior

  1. put the files below into a directory
  2. mockgen -package=deadlock -source=interfaces.go -destination=mocks.go
  3. go test -v .

interfaces.go

package deadlock

import "fmt"

type Outer interface {
	Consume(Inner)
}

type Inner interface {
	fmt.Stringer
}

deadlock_test.go

package deadlock

import (
	"testing"

	"go.uber.org/mock/gomock"
)

func TestDeadlock(t *testing.T) {
	ctrl := gomock.NewController(t)
	inner := NewMockInner(ctrl)
	outer := NewMockOuter(ctrl)
	outer.Consume(inner)
}

Additional Information

  • gomock mode (reflect or source): source
  • gomock version or git ref: v0.3.0
  • golang version: go version go1.21.3 linux/amd64

Triage Notes for the Maintainers

  1. The call to ctrl.T.Fatalf in controller.go:209 is holding ctrl.mu
  2. Fatalf will call the String() method on the mock (also unexpectedly)
  3. this will reach controller.go:200 and deadlock

backtrace

goroutine 18 [sync.Mutex.Lock]:
sync.runtime_SemacquireMutex(0x0?, 0x65?, 0x4be6c0?)
        /usr/local/go/src/runtime/sema.go:77 +0x25
sync.(*Mutex).lockSlow(0xc000196400)
        /usr/local/go/src/sync/mutex.go:171 +0x15d
sync.(*Mutex).Lock(...)
        /usr/local/go/src/sync/mutex.go:90
go.uber.org/mock/gomock.(*Controller).Call.func1(0xc0001963f0, {0x517220?, 0xc000184200}, {0x536f30, 0x6}, {0x0, 0x0, 0x0})
        .../go/pkg/mod/go.uber.org/[email protected]/gomock/controller.go:200 +0xd1                    
go.uber.org/mock/gomock.(*Controller).Call(0xc0001963f0, {0x517220, 0xc000184200}, {0x536f30, 0x6}, {0x0, 0x0, 0x0})
        .../go/pkg/mod/go.uber.org/[email protected]/gomock/controller.go:225 +0xa7                    
.../deadlock.(*MockInner).String(0xc000184200)                        
        /home/.../deadlock/mocks.go:78 +0x53                                  
fmt.(*pp).handleMethods(0xc00019a680, 0x184220?)
        /usr/local/go/src/fmt/print.go:673 +0x2b2
fmt.(*pp).printValue(0xc00019a680, {0x513ea0?, 0xc000184220?, 0x49e866?}, 0x76, 0x1)
        /usr/local/go/src/fmt/print.go:770 +0xca
fmt.(*pp).printValue(0xc00019a680, {0x50dd20?, 0xc0001a8090?, 0x5398db?}, 0x76, 0x0)
        /usr/local/go/src/fmt/print.go:912 +0x1605
fmt.(*pp).printArg(0xc00019a680, {0x50dd20?, 0xc0001a8090}, 0x76)
        /usr/local/go/src/fmt/print.go:759 +0x6a5
fmt.(*pp).doPrintf(0xc00019a680, {0x540a4e, 0x2e}, {0xc000180140?, 0x5, 0x5})
        /usr/local/go/src/fmt/print.go:1077 +0x39e
fmt.Sprintf({0x540a4e, 0x2e}, {0xc000180140, 0x5, 0x5})
        /usr/local/go/src/fmt/print.go:239 +0x53
testing.(*common).Fatalf(0xc00019e680, {0x540a4e?, 0x40ac65?}, {0xc000180140?, 0x50efa0?, 0x61ef01?})
        /usr/local/go/src/testing/testing.go:1082 +0x3f
go.uber.org/mock/gomock.(*Controller).Call.func1(0xc0001963f0, {0x5172a0?, 0xc000184210}, {0x537171, 0x7}, {0xc000184220, 0x1, 0x1})
        .../go/pkg/mod/go.uber.org/[email protected]/gomock/controller.go:209 +0x356                    
go.uber.org/mock/gomock.(*Controller).Call(0xc0001963f0, {0x5172a0, 0xc000184210}, {0x537171, 0x7}, {0xc000184220, 0x1, 0x1})
        .../go/pkg/mod/go.uber.org/[email protected]/gomock/controller.go:225 +0xa7                    
.../deadlock.(*MockOuter).Consume(0xc000184210, {0x5670e0?, 0xc000184200})                        
        /home/.../deadlock/mocks.go:43 +0xab                                  
.../deadlock.TestDeadlock(0x0?)                        
        /home/.../deadlock_test.go:13 +0x129                                           
testing.tRunner(0xc00019e680, 0x542e38)
        /usr/local/go/src/testing/testing.go:1595 +0xff
created by testing.(*T).Run in goroutine 1
        /usr/local/go/src/testing/testing.go:1648 +0x3ad
FAIL    .../deadlock    1.006s
FAIL

Add flag to generate go:generate instruction in the generate file

Requested feature: Add support for a "go:generate" instruction as part of the generated mock files in gomock.

Why the feature is needed: Currently, when using gomock to generate mock files, there is no built-in functionality to include a "go:generate" instruction within the generated mock files.

This instruction is essential for integrating the generated mocks seamlessly into the development workflow; there are already other popular go libraries that do that (for example: hexdigest/gowrap).

Without this feature, users are required to manually add the "go:generate" instruction to each generated mock file, which is time-consuming and prone to human errors, and overall hard to maintain.

(Optional) Proposed solution:
https://github.com/damianopetrungaro/mock/tree/feat_add_go_generate_instruction

Generate typed Times for mocks

Requested feature
Generate typed Times(), just as Return, Do and DoAndReturn

Why the feature is needed
I would like both of these cases supported:

// Supported, Return is typed
m.
  EXPECT().
  Bar(gomock.Eq(101)).
  Return(103).
  Times(1)
// Unsupported, Return is not typed since Times return *gomock.Call
m.
  EXPECT().
  Bar(gomock.Eq(101)).
  Times(1).
  Return(103)

(Optional) Proposed solution:
I added Times to be emitted by mockgen in my repository fork

mock file not valid for generic interfaces

in generic use pkg path in line of code like

  import (
      context "context"
      gomock "go.uber.org/mock/gomock"
      gorm "gorm.io/gorm"
      reflect "reflect"
      entity "wallet-core/domain/entity"
      genericRepository "wallet-core/pkg/genericRepository"
  )
  
  func (m *MockIBaseWalletTemplateRepository) Paginate(arg0 context.Context, arg1 *genericRepository.PaginateQuery) (genericRepository.IPaginateResult[wallet-core/domain/entity.BaseWalletTemplate], error) {
      m.ctrl.T.Helper()
      ret := m.ctrl.Call(m, "Paginate", arg0, arg1)
      ret0, _ := ret[0].(genericRepository.IPaginateResult[wallet-core/domain/entity.BaseWalletTemplate])
      ret1, _ := ret[1].(error)
      return ret0, ret1
  }

bug is : wallet-core/domain/entity.BaseWalletTemplate in return of paginate func mock

I fix bug with use this

  parts := strings.Split(t, "/")
  t = parts[len(parts)-1]

in my local clone project in path mockgen/mockgen.go in top of line 588 and test code with unit tests

Error when mock generating dot import file with different package name

Actual behavior
If your source file contains dot imports and the output package name is different, mockgen's output will be a file that cannot be compiled.

Expected behavior
The output will be a file that can be compiled successfully.

To Reproduce

  1. The source file internal.go, which contains a dot import, is as follows:
package internal

//go:generate go run go.uber.org/mock/mockgen -source=internal.go -destination=mocks/internal_gen.go

import (
	. "context"
)

type WithDotImports interface {
	ImportDot() Context
}
  1. Run go generate ./.... This produces the file mocks/internal_gen.go.

  2. In mocks/internal_gen.go, the return type Context of the ImportDot method is incorrectly qualified as internal.Context, even though such qualification is unnecessary.

package mock_internal

import (
	. "context"
	// ...
)

// ...

func (m *MockWithDotImports) ImportDot() internal.Context {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "ImportDot")
	ret0, _ := ret[0].(internal.Context)
	return ret0
}

Additional Information

  • gomock mode (reflect or source): source (I haven't tried withe reflect, issue might also happen)
  • gomock version or git ref: v0.4.0
  • golang version: 1.21.3

Triage Notes for the Maintainers

Dot import are seldom used.
This bug may not be worth fixing.
So how about adding the following code to after this line.

	if pkg.Name != outputPackageName && len(pkg.DotImports) > 0 {
		log.Fatalf("Different package name specifications including dot imports are not yet supported: %v != %v", pkg.Name, outputPackageName)
	}

Fundamentally, the issue seems to be that parseType method in mockgen/parse.go does not return the correct package name for dot import types.

proposal: Add a `OneOf` Matcher to match parameter as part of a list

Problem Statement

While testing functions with multiple calls to the same method, occasionally we encounter a situation where we require multiple matches for one parameter. One approach would be to create multiple mock.EXPECT() calls for each distinct match, however, with the new gomock.WithOverridableExpectations(), the second call will override the first, regardless of any inclusion of .Times(x).

Regardless of the existing problem with gomock.WithOverridableExpectations(), in some situations it would be convenient to create multiple matches from a single EXPECT, especially if the DoAnyReturn() is complex. So I believe this would help ease-of-use.

Proposal

Include a new OneOf Matcher that will match if a given parameter belongs to the provided list. This will allow for multiple calls to be matched in one EXPECT() with TIMES(N), which temporarily helps solve the Override issue. In addition to this, being able to match one element against a list would be valuable and improve the ease of use when testing if a parameter matches within a given list.

Examples

Example A: Overriding Order

Consider the following function:

func SUT() {
    MockedFunction("Go")
    MockedFunction("Rust")
}

Assume we have created an EXPECT() for Do() and would like to later override it as follows:

mock.EXPECT().MockedFunction("Go").Return(true).Times(1)
mock.EXPECT().MockedFunction("Rust").Return(true).Times(1)

However, with gomock.WithOverridableExpectations() enabled, the 2nd EXPECT() takes precedent and the test fails. One solution to this would then be the following:

mock.EXPECT().
	MockedFunction(gomock.Any()).
	DoAndReturn(func(lang string) bool {
		switch lang {
		case "Go":
			return true
		case "Rust":
			return true
		}
		return false
	}).
	Times(2)
}

This approach allows us to use only one EXPECT call, but requires that we use an Any() Matcher and a default false case for the DoAndReturn. It would be preferable to be able to match on if the element was part of a list of acceptable parameter values, as follows:

mock.EXPECT().
	MockedFunction(gomock.OneOf([]any{"Go", "Rust"})).
	DoAndReturn(func(lang string) bool {
		switch lang {
		case "Go":
			return true
		case "Rust":
			return true
		}
		return false
	}).
	Times(2)
},

Example B: Mocking Convenience

Consider the following function used to determine which animal food you should use, based on your country:

func SUT(country string) Food {
	animal := interface.GetAnimal(country)
	food := interface.GetFood(animal)
	return food
}

// Valid animal types
func GetAnimals() {
  []Animals{
	  Gopher,
    	  Meerkat,
  	  Chinchilla,
  }
}

It may be convenient to stub the call to GetFood for any valid Animal type given. We can do this similarly to above, with a DoAnyReturn, but this again would require using an Any matcher. It would be preferable to be able to provide a list of valid matches, as follows:

func TestSUT(t *testing.T) {
    interfaceMock.EXPECT().
		GetFood({}any{Gopher, Meerkat, Chinchilla}).
		DoAnyReturn(func(animal Animal) Food {
			if animal == Meerkat {
				return Insects
			} 
			return Seeds
		}).AnyTimes()
}

Proposed implementation

I drafted a PR with my proposed implementation in #91

Improve default failed equality match output to more clearly show diffs

Hi, maintainers! I would like to express my sincere gratitude for your efforts in maintaining gomock.

Requested feature
Is the issue golang/mock#616 resolved? If not, i hope improvement the diffs when tests fails.

I didn't find out whether the problem resolved or not as the original repository has the issue archived and cannot ask there.

Why the feature is needed
As showing the original issue, it is often hard to understand and interpret the diffs.

(Optional) Proposed solution
i think we can solve this problem by using the method indicated in the following comments:

Alternatively, adding an option to change the default matcher may resolve this, as it would allow for the use of this way.

deprecation of `Controller.Finish` breaks certain test frameworks

Actual behavior

When using the Ginkgo test framework, there's only a single TestXXX function. This function call all other test functions written in the Ginkgo framework. When using gomock, users will need to manually call the gomock.Controller.Finish method after each test.

Expected behavior

gomock.Controller.Finish needs to be available, and needs to remain so in the future. #50 deprecated this function, which makes staticcheck emit errors on my test code. That's ok (I can add nolint directives), but I'm worried that the deprecation is a first step to an eventual remove of Finish, which would break my entire test setup in quic-go. (For the record, I'm not happy with Ginkgo, but that's what we're stuck with for the moment, see quic-go/quic-go#3652).

Given that there are valid use cases of Finish, the function should probably not deprecated at all. Instead, documentation could be added explaining that usually (i.e. when not using any test framework) it's not necessary to call that function.

Additional Information

  • gomock mode (reflect or source): both
  • gomock version or git ref: 837f20a
  • golang version: Go 1.21.1

Triage Notes for the Maintainers

Order of calls is enforced when InOrder() or After() were not invoked

This bug is still around:


Actual behaviour
When I have EXPECT set for two calls to the same method with different parameters - the order of EXPECT definitions enforces the order of the actual calls.

I.e. when having these expectations defined:

test.mock.EXPECT().DoSomething("foo").Return(&Response{})
test.mock.EXPECT().DoSomething("bar").Return(&Response{})

and code under test defined as

service.DoSomething("foo")
service.DoSomething("bar")

Just changing the order of definitions of calls expected with no other changes, i.e. making it

test.mock.EXPECT().DoSomething("bar").Return(&Response{})
test.mock.EXPECT().DoSomething("foo").Return(&Response{})
makes the test fail.

Expected behavior
As per documentation:

By default, expected calls are not enforced to run in any particular order.

So no order should be enforced as long as the actual calls match any of the defined expectations.

Command line flag to toggle whether to emit source file/interface names comment in generated code

Requested feature
I want to toggle whether to emit a comment of mock's origin (a .go file for source mode, a package and interface names for reflect mode) in a generated code like below (from example code):

// Source: go.uber.org/mock/sample (interfaces: Index,Embed,Embedded)

Why the feature is needed
I made a wrapper tool of mockgen (named bulkmockgen), which manages interfaces to be mocked with a variable in a .go file and invokes mockgen with symbols arguments from the variable.

For example, running go generate with the below code will execute a command mockgen -package mock_foo -destination ./mock_foo/mock.go . IFoo,IBar.

//go:generate bulkmockgen Iset -- -package mock_foo -destination ./mock_foo/mock.go
var Iset = []any{
	new(IFoo),
	new(IBar),
}

This works fine, but there is a problem that the generated code's comment causes many Git conflicts because there are original interface names in one line in a top of generated code and the line is edited every time I add an interface name to mock target list.

(Optional) Proposed solution
Adding a command line flag like -write_source_comment and controlling whether to emit mock's origin comment by the flag will solve the problem described above.
I implemented it in my repository fork.

Adding method to Controller allowing to check whether all expected calls have been made

I originally created this issue in February 2022 in the golang/mock repository. But as this project has been abandoned in favour of this fork I will suggest the feature over here too.

I want to be able to check whether all expected calls have been made before Controller#Finish() gets invoked as the code being tested is running asynchronously and I can only approximate when all calls will have been made.

This addition should allow it to check whether all expected calls towards the mock(s) have been made in an idempotent way.
This is useful when testing asynchronous/non-deterministic things that aren't fully under the developers control (e.g., in end-2-end tests).

If necessary I can elaborate on my specific testing scenario.

Having such a method allows the user to write something like

require.Eventually(t, mockCtrl.AllExpectedCallsSatisfied, 60time.Second, 100time.Millisecond)
instead of having to wait for an approximated amount of time (which slows down the tests unnecessarily) in order to make sure all expected calls have been satisfied before Controller#Finish() gets invoked.

Why is this needed? Because right now AFAIU I have to add a sleep for an amount of time I approximate to be enough for my system to be done with its work. This is not nice for several reasons:

It's dangerous (and a bad idea in general) because my estimation could be too little and calls have not been made at that point
It's slow because I basically have to approximate very conservatively due to the problem described above.

I already created an MR in golang/mock (golang/mock#627), which I could easily recreate over here.

Add a matcher for checking a string parameter against regex

Requested feature

I've found times where it would be useful to check that string parameters being passed to a function match against some regex.

A specific example could be an SQS message body string containing a UUID that was generated during execution and I won't know what it is ahead of time, but I want to check against the majority of the body being passed to the mock, even though I don't care exactly what the UUID is.

sqsClient.
  EXPECT().
  SendMessage(gomock.AssignableToTypeOf(context.Background()), gomock.Regex(expectedMessageBodyRegex))

Why the feature is needed

I've created a custom matcher for my use cases, but thought I'd offer it up here with an issue and PR in case you could see it being useful.

(Optional) Proposed solution

PR to follow very shortly, see below

Provide a new flag that makes the generated constructor function private

In my code, there are some private interfaces that should only be accessed within the current package. However, when I use gomock to generate mock code, other packages can call NewmockXXX to create a mock of those interfaces, which is not what we expect. I would like to achieve a functionality similar to the following:

...
	private            = flag.Bool("private", false, "Generate private constructor functions for all mocks")
...
...
	newStr := "New"
	if *private {
		newStr = "new"
	}
	g.p("// "+newStr+"%v creates a new mock instance.", mockType)
	g.p("func "+newStr+"%v%v(ctrl *gomock.Controller) *%v%v {", mockType, longTp, mockType, shortTp)
	g.in()
...

Generating mocks on a file with a dot import creates a compilation error

Actual behavior When generatinga mock from a source file which contains a dot import, the dot import is copied in the destination file. If the dot import is not actually used, the compiler then fails.

Expected behavior Generated code always compiles, even if someone decides to add a dot import in their code.

To Reproduce I created an example of the issue here.

  1. Have mockgen installed.
  2. Clone this repo or copy the following code into a main.go file:
    import . "fmt"
    
    //go:generate mockgen -source=main.go -destination=mocks/main.go
    type I interface{}
    
    func main() {
        /* fmt. */ Println("Hello world!")
    }
  3. Run go generate ./...
  4. Run go build ./... - the compilation fails with error: mocks/main.go:13:2: "fmt" imported and not used.

Additional Information

  • gomock mode (reflect or source): source (I haven't tried withe reflect, issue might also happen)
  • gomock version or git ref: v0.4.0
  • golang version: 1.21.4

Triage Notes for the Maintainers

Workaround

The easy and sane workaround that I will apply is just to not have dot imports. I thought it was still useful to report the bug though...

v0.1.0 Release

We'll be tagging a v0.1.0 release with the current master branch, which does not have any additional features from the upstream golang/mock project (other than import path). This will serve as a base point before we put in more features to this.

Following this we'll start reviewing community contributed PRs as well as address internal users' bug fix and feature requests.

ERROR: cannot find module providing package go.uber.org/mock/mockgen/model: import lookup disabled by -mod=vendor

Actual behavior
Moving from golang/mock I got this error when running the mockgen command and using reflection:

mockgen -build_flags=-mod=vendor -destination=internal/testing/mock/mock_dynamodbiface.go -package=mock github.com/aws/aws-sdk-go/service/dynamodb/dynamodbiface DynamoDBAPI
prog.go:12:2: cannot find module providing package go.uber.org/mock/mockgen/model: import lookup disabled by -mod=vendor
prog.go:12:2: cannot find module providing package go.uber.org/mock/mockgen/model: import lookup disabled by -mod=vendor
build flag -mod=vendor only valid when using modules
2023/09/11 16:50:04 Loading input failed: exit status 1

Expected behavior
This doesn't happen with golang/mock module

To Reproduce

  1. go install go.uber.org/mock/mockgen@latest
  2. mockgen -build_flags=-mod=vendor -destination=internal/testing/mock/mock_dynamodbiface.go -package=mock github.com/aws/aws-sdk-go/service/dynamodb/dynamodbiface DynamoDBAPI

Additional Information

  • gomock mode (reflect or source): reflect
  • gomock version or git ref: v0.2.0
  • golang version: go version go1.21.1 darwin/arm64

Triage Notes for the Maintainers

Do() should panic when given a function that returns values

I've just spent an hour debugging a test where I by mistake used Do(func () string { ... return "some value" }) instead of DoAndReturn(). Do() just discarded the value and mock returned an empty string.

Do() should error out ASAP when given a function that returns values.

Thank you for the library!

Flag for interface exclusion

Please add the ability to exclude interfaces, if source mode of mockgen is used.

This can be useful in the following case:

package segmentation

//go:generate mockgen -destination=segmenter_mock.go -package=segmentation -source=segmenter.go

// need to exlude this interface, because it is constraint
type Segment interface {
	~int
}

type Segmenter[V Segment] interface {
	Segment(code string) V
}

You can do this by passing a flag or using a comment like // gomock:exclude

Support specifying interfaces to mock when using source mode

Requested feature A clear description of the desired feature and an example of
how it would be used.

As far as I can tell, there is no way to specify which interfaces to mock out of a file when using source mode

Why the feature is needed A clear description of how this feature is not
served by existing functionality in gomock.

The closest you can get to this functionality is manually passing in every interface other than the one you want to mock in -exclude_interfaces

(Optional) Proposed solution A clear description of a proposed method for
adding this feature to gomock.

Adding an -interfaces flag which auto-computes the -exclude_interfaces flag would be relatively straightforward I think.

gob.Register panics on model types conflict

Actual behavior A clear and concise description of what the bug is.

When running this uber mockgen in a codebase with reference to the golang mockgen, the reflect program would panic on the gob.Register call:

panic: gob: registering duplicate types for "*model.ArrayType": *model.ArrayType != *model.ArrayType

goroutine 1 [running]:
encoding/gob.RegisterName({0x10fad4f, 0x10}, {0x110b460, 0xc000010468})
        /usr/local/go/src/encoding/gob/type.go:820 +0x3f4
encoding/gob.Register({0x110b460, 0xc000010468})
        /usr/local/go/src/encoding/gob/type.go:874 +0x1c5
github.com/golang/mock/mockgen/model.init.0()
        $HOME/workshop/go/pkg/mod/github.com/golang/[email protected]/mockgen/model/model.go:146 +0x39
panic: gob: registering duplicate types for "*model.ArrayType": *model.ArrayType != *model.ArrayType
...

Expected behavior A clear and concise description of what you expected to
happen.

This is because in our code base (or similar code base created before go mod area) contains import path like this:

_ "github.com/golang/mock/mockgen/model"

This call will register the model types with the same name, and result in gob panic. This import call is suggested by golang mockgen as a workaround for vendor usage:

https://github.com/golang/mock#reflect-vendoring-error

I believe this would be a blocker for migrating from golang mockgen as upstream libraries might have such import path, and it would take time to migrate all these upstream libraries as it requires multiple steps.

Therefore, I would like to propose a fix to register these model types with a prefix.

To Reproduce Steps to reproduce the behavior

To produce this issue, please check out this commit: https://github.com/bcho/gomock-migrate/tree/4148048b8a313fa0be6164d1cdcdc941e523c0c1

I have a fix poc in this commit: https://github.com/bcho/gomock-migrate/tree/2de73982ee899e4e0a3986a021b584c08feb3e5f , which updated the uber gomock to use the fixed model in my local fork.

Additional Information

  • gomock mode (reflect or source): reflect
  • gomock version or git ref: 0.2.0
  • golang version: go version go1.20.2 darwin/amd64

Triage Notes for the Maintainers

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.