-
Notifications
You must be signed in to change notification settings - Fork 412
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add github.com/matryer/moq style mocks into mockery #725
base: master
Are you sure you want to change the base?
Conversation
@breml @sudo-suhas are |
@LandonTClipp Yes, it is possible to have multiple mock implementations (from different interfaces) in a single file. given a file: package file
type Foo interface {
Bar()
}
type Baz interface {
Bazer() error
} the command moq -fmt goimports -pkg file_test -out file_gen_test.go . Foo Baz would generate a single file named This is also mentioned in the README.md in the usage section. The relevant sections in the code:
|
Awesome, thanks for clarifying. This will be a bit of a roadblock as mockery has no way to do this currently so I will need to think how I will go about it. |
* Internal registry for disambiguated imports, vars - Move functionality in the moq package partially into internal/{registry,template}. - Leverage registry to assign unique package and variable/method parameter names. Use import aliases if present in interface source package. BREAKING CHANGE: When the interface definition does not mention the parameter names, the field names in call info anonymous struct will be different. The new field names are generated using the type info (string -> s, int -> n, chan int -> intCh, []MyType -> myTypes, map[string]int -> stringToInt etc.). For example, for a string parameter previously if the field name was 'In1', the new field could be 'S' or 'S1' (depends on number of string method parameters). * Refactor golden file tests to be table-driven * Fix sync pkg alias handling for moq generation * Improve, add tests (increase coverage) * Use $.Foo in template, avoid declaring variables $ is set to the data argument passed to Execute, that is, to the starting value of dot. Variables were declared to be able to refer to the parent context. * Consistent template field formatting * Use tabs in generated Godoc comments' example code * Minor simplification * go generate * Fix conflict for generated param name of pointer type Excellent work by @sudo-suhas.
Allow the generation of mocks for generics as introduced in golang 1.18
By tweaking whitespace in template
The optional with-resets flag adds methods to reset method calls. Calls can be reset individually or all at once with these.
* Internal registry for disambiguated imports, vars - Move functionality in the moq package partially into internal/{registry,template}. - Leverage registry to assign unique package and variable/method parameter names. Use import aliases if present in interface source package. BREAKING CHANGE: When the interface definition does not mention the parameter names, the field names in call info anonymous struct will be different. The new field names are generated using the type info (string -> s, int -> n, chan int -> intCh, []MyType -> myTypes, map[string]int -> stringToInt etc.). For example, for a string parameter previously if the field name was 'In1', the new field could be 'S' or 'S1' (depends on number of string method parameters). * Refactor golden file tests to be table-driven * Fix sync pkg alias handling for moq generation * Improve, add tests (increase coverage) * Use $.Foo in template, avoid declaring variables $ is set to the data argument passed to Execute, that is, to the starting value of dot. Variables were declared to be able to refer to the parent context. * Consistent template field formatting * Use tabs in generated Godoc comments' example code * Minor simplification * go generate * Fix conflict for generated param name of pointer type Excellent work by @sudo-suhas.
When the type and the package name is the same for an anonymous parameter (ex: time.Time), and there are more than 1 such parameters, the generated name for both was the same. And the generated code would not be valid. Fix the bug by ensuring the parameter name does not conflict with package imports first before checking against other parameter names.
When a custom type has a name that can shadow an in-built type, append MoqParam to the name. Example: var name stringMoqParam for null.String.
Allow the generation of mocks for generics as introduced in golang 1.18
When we generate a unique name for pkg a on conflict with pkg b, the new name could already be in use for pkg c. So recursively check each unique name against existing imports before setting it.
- Add benchmark test for registry.New
…methods In this commit, we gather all the template data needed by the moq logic to generate its template. This is untested as of yet. TODO: need to start testing this works by calling upon `moq` in `.mockery.yaml`.
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## master #725 +/- ##
====================================================
- Coverage 42.71105% 30.33787% -12.37319%
====================================================
Files 63 111 +48
Lines 4987 7133 +2146
====================================================
+ Hits 2130 2164 +34
- Misses 2657 4763 +2106
- Partials 200 206 +6 ☔ View full report in Codecov by Sentry. |
In this PR, we have a mostly working implementation of moq-in-mockery. Please let me know your thoughts, I would really appreciate a thorough review to make sure I haven't missed something important! Thanks. |
I did some initial tests and it looks like I am failing to reproduce my mocks with mockery. Currently I am facing the following issues: I have a file named
On an other example I tried to generate a mock from a type alias: type TelemetryClient = appinsights.TelemetryClient It looks like the type |
We don't currently have a template variable that provides to you the filename of where the interface was defined. The tricky part of this right now is that if you have multiple interfaces in a single file, mockery would not be able to represent that currently because we're restricted to only a single mock per file. That's a feature change I intend to make in a different PR because it will require a fair amount of effort.
Perhaps I don't understand your intention here, but if you want the mock to live physically next to the file, you need to set
Yeah these are notoriously tricky. You have to use Edit: it turns out there has been some progress made in Edit 2: very interesting, using the
|
Yes, I want the mock to live physically next to the file and yes I do have Could it be, that the source of the problem is, that the signature of the interface, that is mocked, accepts a parameter, which is again an interface from the same package? This is the config I have: quiet: False
disable-version-string: True
with-expecter: True
style: moq
mockname: "{{.InterfaceName}}Mock"
packages:
github.com/breml/pkg:
config:
dir: "{{.InterfaceDir}}"
filename: "adapter_notification_mock_test.go"
style: moq
outpkg: "{{.PackageName}}"
inpackage: True
interfaces:
NotificationAdapter: With package pkg
import "context"
type NotificationAdapter interface {
Notify(ctx context.Context, itemKey string, item Publication) error
} and package pkg
type Publication interface {
ID() string
Name() string
} I get // Code generated by mockery; DO NOT EDIT.
// github.com/vektra/mockery
package pkg
import (
"context"
"sync"
"github.com/breml/pkg"
)
// Ensure, that NotificationAdapterMock does implement NotificationAdapter.
// If this is not the case, regenerate this file with moq.
var _ NotificationAdapter = &NotificationAdapterMock{}
// NotificationAdapterMock is a mock implementation of NotificationAdapter.
//
// func TestSomethingThatUsesNotificationAdapter(t *testing.T) {
//
// // make and configure a mocked NotificationAdapter
// mockedNotificationAdapter := &NotificationAdapterMock{
// NotifyFunc: func(ctx context.Context, itemKey string, item pkg.Publication) error {
// panic("mock out the Notify method")
// },
// }
//
// // use mockedNotificationAdapter in code that requires NotificationAdapter
// // and then make assertions.
//
// }
type NotificationAdapterMock struct {
// NotifyFunc mocks the Notify method.
NotifyFunc func(ctx context.Context, itemKey string, item pkg.Publication) error
... Both files ( If I remove the |
I see, that gives me more clarity. I'll need to dig into why that's happening. Most of the logic being used to generate moq is mostly identical to the original repo so I'll need to figure out why it's different in this case. |
inpackage generation fixed in |
Description
This PR implements a new
style
parameter that, if set tomoq
, will generate the matryer/moq-based mocks. The shape of the moq mocks is essentially the same as the original project. I have successfully been able to build a large number of our test fixtures using moq.Copied over initial files from matryer/moq using https://blog.billyc.io/how-to-copy-one-or-more-files-from-one-git-repo-to-another-and-keep-the-git-history/. I attempted to get Git attribution for any code copied from the moq project, but I may have missed some lines here or there. There were also some minor modifications I did to the
moq.templ
file to fix some bugs I noticed.Implements the proposal in #715.
Configuration
I have elected to make mockery itself agnostic to the template-specific variables inside of
moq
, likewith-resets
,skip-ensure
etc. These are simply passed through to the template as a black-box map, instead of unmarshalling it into a struct. The reason is because I intend to extend mockery to accept any arbitrarily defined template, so end users would need to pass arbitrary config to their template.Note that I have excluded some fixtures that were not compiling correctly. I believe these probably couldn't be compiled in the original
moq
project, although I haven't explicitly checked.Output Mocks
You can see the moq-generated mocks, starting here: https://github.com/vektra/mockery/pull/725/files#diff-9efb8f179359bcc43fdae6aa075947a1bb80b511bbae81dd82b743939f874bf3
Feature Tracker
This table tracks the features provided in the
moq.templ
file and the progress made in this PR to plumb the logic through.comparable
, the generated mock is invalid). Not sure if it doesn't work in originalmoq
project, we should check.TODO
KNOWN BUGS
*unsafe.Pointer
. The reason is that theunsafe.Pointer
type does not match any switch case in theMethodScope.populateImports
method. This appears to be an existing bug withmoq
, so we will not address it here.comparable
, when using a generic interface: seeRequesterGeneric
fixture.