diff --git a/README.md b/README.md index ed5d8eaa..7687c57f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ mockery ======= -[![Release](https://github.com/vektra/mockery/actions/workflows/release.yml/badge.svg)](https://github.com/vektra/mockery/actions/workflows/release.yml) [![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/github.com/vektra/mockery/v3?tab=overview) ![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/vektra/mockery) ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/vektra/mockery) [![Go Report Card](https://goreportcard.com/badge/github.com/vektra/mockery)](https://goreportcard.com/report/github.com/vektra/mockery) [![codecov](https://codecov.io/gh/vektra/mockery/branch/master/graph/badge.svg)](https://codecov.io/gh/vektra/mockery) +[![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/github.com/vektra/mockery/v3/template) ![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/vektra/mockery) ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/vektra/mockery) [![Go Report Card](https://goreportcard.com/badge/github.com/vektra/mockery)](https://goreportcard.com/report/github.com/vektra/mockery) [![codecov](https://codecov.io/gh/vektra/mockery/branch/master/graph/badge.svg)](https://codecov.io/gh/vektra/mockery) mockery provides the ability to easily generate mocks for Golang interfaces using the [stretchr/testify/mock](https://pkg.go.dev/github.com/stretchr/testify/mock?tab=doc) package. It removes the boilerplate coding required to use mocks. diff --git a/docs/changelog.md b/docs/changelog.md deleted file mode 100644 index e7c1894c..00000000 --- a/docs/changelog.md +++ /dev/null @@ -1,121 +0,0 @@ -Changelog -========= - -This changelog describes major feature additions. Please view the `releases` page for more details on commits and minor changes. - -### :octicons-tag-24: [`v2.29.0`](https://github.com/vektra/mockery/releases/tag/v2.29.0) template functions - -This release adds a large number of template functions available for use in the `packages` templating engine. - -### :octicons-tag-24: [`v2.25.0`](https://github.com/vektra/mockery/releases/tag/v2.25.0) `recursive` config - -The `recursive` parameter allows mockery to dynamically discover sub-packages when using the `packages` config. - -### :octicons-tag-24: [`v2.24.0`](https://github.com/vektra/mockery/releases/tag/v2.24.0) `exclude` config - -The `exclude` parameter allows you to define subpaths to ignore. This is currently only compatible when using non-`packages` config. - -### :octicons-tag-24: [`v2.23.0`](https://github.com/vektra/mockery/releases/tag/v2.23.0) Replace Types - -The `replace-type` parameter allows adding a list of type replacements to be made in package and/or type names. -This can help overcome issues like usage of type aliases that point to internal packages. - -### :octicons-tag-24: [`v2.21.0`](https://github.com/vektra/mockery/releases/tag/v2.21.0): `#!yaml packages` configuration - -In this version we release the `#!yaml packages` configuration section. This new parameter allows defining specific packages to generate mocks for, while also giving fine-grained control over which interfaces are mocked, where they are located, and how they are configured. Details are provided [here](features.md#packages-configuration). - -Community input is desired before we consider deprecations of dynamic walking (via `#!yaml all: True`): https://github.com/vektra/mockery/discussions/549 - -### :octicons-tag-24: [`v2.20.0`](https://github.com/vektra/mockery/pull/538): Improved Return Value Functions - -Return value functions that return an entire method's return value signature can now be provided. - -```go -proxyMock := mocks.NewProxy(t) -proxyMock.On("passthrough", mock.AnythingOfType("context.Context"), mock.AnythingOfType("string")). -Return( - func(ctx context.Context, s string) (string, error) { - return s, nil - } -) -``` - -You may still use the old way where one function is provided for each return value: - -```go -proxyMock := mocks.NewProxy(t) -proxyMock.On("passthrough", mock.AnythingOfType("context.Context"), mock.AnythingOfType("string")). -Return( - func(ctx context.Context, s string) string { - return s - }, - func(ctx context.Context, s string) error { - return nil - }, -) -``` - -### :octicons-tag-24: [`2.19.0`](https://github.com/vektra/mockery/releases/tag/v2.19.0): `inpackage-suffix` option - -When `inpackage-suffix` is set to `True`, mock files are suffixed with `_mock` instead of being prefixed with `mock_` for InPackage mocks - - -### :octicons-tag-24: [`v2.16.0`](https://github.com/vektra/mockery/pull/527): Config Search Path - -Mockery will iteratively search every directory from the current working directory up to the root path for a `.mockery.yaml` file, if one is not explicitly provided. - -### :octicons-tag-24: [`v2.13.0`](https://github.com/vektra/mockery/pull/456): Generics support - -Mocks are now capable of supporting Golang generics. - -### :octicons-tag-24: [`v2.11.0`](https://github.com/vektra/mockery/pull/406): Mock constructors - -Mockery v2.11 introduces constructors for all mocks. This makes instantiation and mock registration a bit easier and -less error-prone (you won't have to worry about forgetting the `AssertExpectations` method call anymore). - -Before v2.11: -```go -factory := &mocks.Factory{} -factory.Test(t) // so that mock does not panic when a method is unexpected -defer factory.AssertExpectations(t) -``` - -After v2.11: -```go -factory := mocks.NewFactory(t) -``` - -The constructor sets up common functionalities automatically -- The `AssertExpectations` method is registered to be called at the end of the tests via `t.Cleanup()` method. -- The testing.TB interface is registered on the `mock.Mock` so that tests don't panic when a call on the mock is unexpected. - -### :octicons-tag-24: [`v2.10.0`](https://github.com/vektra/mockery/pull/396): Expecter Structs - -Mockery now supports an "expecter" struct, which allows your tests to use type-safe methods to generate call expectations. When enabled through the `with-expecter: True` mockery configuration, you can enter into the expecter interface by simply calling `.EXPECT()` on your mock object. - -For example, given an interface such as -```go -type Requester interface { - Get(path string) (string, error) -} -``` - -You can use the type-safe expecter interface as such: -```go -requesterMock := mocks.NewRequester(t) -requesterMock.EXPECT().Get("some path").Return("result", nil) -requesterMock.EXPECT(). - Get(mock.Anything). - Run(func(path string) { fmt.Println(path, "was called") }). - // Can still use return functions by getting the embedded mock.Call - Call.Return(func(path string) string { return "result for " + path }, nil) -``` - -### :octicons-tag-24: [`v2.0.0`](https://github.com/vektra/mockery/releases/tag/v2.0.0): Major Update - -This is the first major update of mockery. Version 2 brings a handful of improvements to mockery: - -- Structured and pretty console logging -- CLI now switches over to sp13/cobra -- Use of viper configuration parsing. You can now use a .mockery.yaml config file in your repository -- Various CI fixes and improvements diff --git a/docs/deprecations.md b/docs/deprecations.md deleted file mode 100644 index 3c7b699b..00000000 --- a/docs/deprecations.md +++ /dev/null @@ -1,93 +0,0 @@ -Deprecations -============= - -`packages` ----------- - -!!! tip "" - - To resolve this warning, use the [`packages`](features.md#packages-configuration) feature: - - ```yaml title=".mockery.yaml" - packages: - [...] - ``` - -The [`packages`](features.md#packages-configuration) feature will be the only way to configure mockery in the future. - -`issue-845-fix` ---------------- - -!!! tip "" - - To resolve this warning: - - ```yaml title=".mockery.yaml" - issue-845-fix: True - ``` - -This parameter fixes a somewhat uninteresting, but important issue found in [#845](https://github.com/vektra/mockery/issues/845). -In short, mockery ignored the `#!yaml outpkg:` parameter if `#!yaml inpackage:` was set to `#!yaml True`. This prevents users -from being able to set alternate package names for their mocks that are generated in the same directory -as the mocked interface. For example, it's legal Go to append `_test` to the mock package name -if the file is appended with `_test.go` as well. This parameter will be permanently -enabled in mockery v3. - -As an example, if you had configuration that looked like this: - -```yaml -all: True -dir: "{{.InterfaceDir}}" -mockname: "{{.InterfaceName}}Mock" -outpkg: "{{.PackageName}}_test" -filename: "mock_{{.InterfaceName}}_test.go" -inpackage: True -``` - -The `#!yaml outpkg` parameter would not be respected and instead would be forced to take on the value of `#!yaml "{{.PackageName}}"`. -To remove the warning, you must set: - -```yaml -issue-845-fix: True -``` - -After this is done, mocks generated in the old scheme will properly respect the `#!yaml outpkg:` parameter previously set -if being generated with `#!yaml inpackage: True`. - -`resolve-type-alias` --------------------- - -!!! tip "" - - To resolve this warning: - - ```yaml title=".mockery.yaml" - resolve-type-alias: False - ``` - -This parameter directs Mockery on whether it should resolve a type alias to its underlying, real -type or if it should generate mocks by referencing the alias. Mockery was changed in [#808](https://github.com/vektra/mockery/pull/808) -to support a new language feature that exposed type aliases in the parsed syntax tree. This meant -that Mockery was now explicitly aware of aliases, which fixed a number of problems: - -- [#803](https://github.com/vektra/mockery/pull/803) -- [#331](https://github.com/vektra/mockery/issues/331) - -However, it was discovered in [#839](https://github.com/vektra/mockery/issues/839) that this was in fact a backwards-incompatible change. Thus, to maintain backwards compatability guarantees, we created this parameter that will be set to `True` by default. - -For all new projects that use Mockery, there is no reason to resolve type aliases so this parameter should almost always -be set to `False`. This will be the permanent behavior in Mockery v3. - -`with-expecter` ---------------- - -!!! tip "" - - To resolve this warning: - - ```yaml title=".mockery.yaml" - with-expecter: True - ``` - -This parameter enables the [expecter structs](features.md#expecter-structs). In Mockery v3, this parameter will be permanently -enabled. In order to remove the deprecation warning, you must set this parameter to `#!yaml with-expecter: True`. \ No newline at end of file diff --git a/docs/examples.md b/docs/examples.md deleted file mode 100644 index 119a5596..00000000 --- a/docs/examples.md +++ /dev/null @@ -1,140 +0,0 @@ -Examples -======== - -!!! tip - IDEs are really useful when interacting with mockery objects. All mockery objects embed the [`github.com/stretchr/testify/mock.Mock`](https://pkg.go.dev/github.com/stretchr/testify/mock#Mock) object so you have access to both methods provided by mockery, and from testify itself. IDE auto-completion will show you all methods available for your use. - -### Simple case - -Given this interface: - -```go title="string.go" -package example_project - -type Stringer interface { - String() string -} -``` - -Create a mock for this interface by specifying it in your config. We can then create a test using this new mock object: - -```go title="string_test.go" -package example_project - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func Foo(s Stringer) string { - return s.String() -} - -func TestString(t *testing.T) { - mockStringer := NewMockStringer(t) - mockStringer.EXPECT().String().Return("mockery") - assert.Equal(t, "mockery", Foo(mockStringer)) -} -``` - -Note that in combination with using the mock's constructor and the [`.EXPECT()`](features.md#expecter-structs) directives, your test will automatically fail if the expected call is not made. - -??? tip "Alternate way of specifying expectations" - - You can also use the `github.com/stretchr/testify/mock.Mock` object directly (instead of using the `.EXPECT()` methods, which provide type-safe-ish assertions). - - ```go title="string_test.go" - func TestString(t *testing.T) { - mockStringer := NewMockStringer(t) - mockStringer.On("String").Return("mockery") - assert.Equal(t, "mockery", Foo(mockStringer)) - } - ``` - - We recommend always interacting with the assertions through `.EXPECT()` as mockery auto-generates methods that call out to `Mock.On()` themselves, providing you with some amount of compile-time safety. Consider if all your expectations for `String()` use the `Mock.On()` methods, and you decide to add an argument to `String()` to become `String(foo string)`. Now, your existing tests will only fail when you run them. If you had used `.EXPECT()` and regenerated your mocks after changing the function signature, your IDE, and the go compiler itself, would both tell you immediately that your expectations don't match the function signature. - -### Function type case - -!!! bug - Generating mocks for function types is likely not functioning in the `packages` config semantics. You'll likely need to revert to the legacy semantics as shown below. - -Given this is in `send.go` - -```go -package test - -type SendFunc func(data string) (int, error) -``` - -Run: `mockery --name=SendFunc` and the following will be output: - -```go title="mock_SendFunc_test.go" -package mocks - -import ( - "github.com/stretchr/testify/mock" - - testing "testing" -) - -type SendFunc struct { - mock.Mock -} - -func (_m *SendFunc) Execute(data string) (int, error) { - ret := _m.Called(data) - - var r0 int - if rf, ok := ret.Get(0).(func(string) int); ok { - r0 = rf(data) - } else { - r0 = ret.Get(0).(int) - } - - var r1 error - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(data) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NewSendFunc creates a new instance of SendFunc. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewSendFunc(t testing.TB) *SendFunc { - mock := &SendFunc{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} -``` - -### Return Value Provider Functions - -If your tests need access to the arguments to calculate the return values, -set the return value to a function that takes the method's arguments as its own -arguments and returns the return value. For example, given this interface: - -```go -package test - -type Proxy interface { - passthrough(ctx context.Context, s string) string -} -``` - -The argument can be passed through as the return value: - -```go -import . "github.com/stretchr/testify/mock" - -proxyMock := mocks.NewProxy(t) -proxyMock.On("passthrough", mock.AnythingOfType("context.Context"), mock.AnythingOfType("string")). - Return(func(ctx context.Context, s string) string { - return s - }) -``` diff --git a/docs/notes.md b/docs/faq.md similarity index 100% rename from docs/notes.md rename to docs/faq.md diff --git a/docs/features.md b/docs/template-mockery.md similarity index 54% rename from docs/features.md rename to docs/template-mockery.md index 618f9331..4fcb9103 100644 --- a/docs/features.md +++ b/docs/template-mockery.md @@ -1,8 +1,192 @@ -Features -======== +--- +title: Mockery +--- -Replace Types -------------- +Mockery +======= + +Features for `#!yaml template: mockery`. + +Choosing this template will render a traditional "mockery-style" template. The +section below shows what will be rendered for the given interface. + +## Description + +=== "Interface" + + ```go + package test + + type Requester interface { + Get(path string) (string, error) + } + ``` + +=== "`.mockery.yml`" + + ```yaml + template: mockery + packages: + github.com/vektra/mockery/v3/pkg/fixtures: + config: + dir: "{{.InterfaceDir}}" + filename: "mocks.go" + pkgname: "test" + mockname: "Mock{{.InterfaceName}}" + interfaces: + Requester: + ``` + +=== "`mocks.go`" + + ```go + // Code generated by mockery; DO NOT EDIT. + // github.com/vektra/mockery + + package test + + import ( + mock "github.com/stretchr/testify/mock" + ) + + + // NewRequester creates a new instance of Requester. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. + // The first argument is typically a *testing.T value. + func NewRequester (t interface { + mock.TestingT + Cleanup(func()) + }) *Requester { + // ... + } + + + // Requester is an autogenerated mock type for the Requester type + type Requester struct { + mock.Mock + } + + type Requester_Expecter struct { + mock *mock.Mock + } + + func (_m *Requester) EXPECT() *Requester_Expecter { + // ... + } + + + + // Get provides a mock function for the type Requester + func (_mock *Requester) Get(path string) (string, error) { + // ... + } + + + + // Requester_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' + type Requester_Get_Call struct { + *mock.Call + } + + + + // Get is a helper method to define mock.On call + // - path + func (_e *Requester_Expecter) Get(path interface{}, ) *Requester_Get_Call { + // ... + } + + func (_c *Requester_Get_Call) Run(run func(path string)) *Requester_Get_Call { + // ... + } + + func (_c *Requester_Get_Call) Return(s string, err error) *Requester_Get_Call { + // ... + } + + func (_c *Requester_Get_Call) RunAndReturn(run func(path string)(string, error)) *Requester_Get_Call { + // ... + } + ``` + +=== "Example Usage" + + ```go + package test + + import ( + "testing" + + "github.com/stretchr/testify/assert" + ) + + func TestRequesterMock(t *testing.T) { + m := NewMockRequester(t) + m.EXPECT().Get("foo").Return("bar", nil).Once() + retString, err := m.Get("foo") + assert.NoError(t, err) + assert.Equal(t, retString, "bar") + } + ``` + +As you can see, this mock utilizes `github.com/stretchr/testify` under the hood and registers call expectations with testify. When the mock receives a call to `Get()`, it retrieves the expected value from testify to be returned. + +This style of mock also has other interesting methods: + +=== "`#!go Run()`" + + Run a side effect when the argument matches. + + ```go + func TestRequesterMockRun(t *testing.T) { + m := NewMockRequester(t) + m.EXPECT().Get(mock.Anything).Return("", nil) + m.EXPECT().Get(mock.Anything).Run(func(path string) { + fmt.Printf("Side effect! Argument is: %s", path) + }) + retString, err := m.Get("hello") + assert.NoError(t, err) + assert.Equal(t, retString, "") + } + ``` + +=== "`#!go RunAndReturn()`" + + Run a function to perform side-effects, and return the result of the function. + + ```go + func TestRequesterMockRunAndReturn(t *testing.T) { + m := NewMockRequester(t) + m.EXPECT().Get(mock.Anything).RunAndReturn(func(path string) (string, error) { + return path + " world", nil + }) + retString, err := m.Get("hello") + assert.NoError(t, err) + assert.Equal(t, retString, "hello world") + } + ``` + +=== "`github.com/stretchr/testify/mock.Mock`" + + Because the mock embeds the testify `Mock` object, you can all any methods on that as well. + + ```go + func TestRequesterMockTestifyEmbed(t *testing.T) { + m := NewMockRequester(t) + m.EXPECT().Get(mock.Anything).Return("", nil).Twice() + m.Get("hello") + m.Get("world") + assert.Equal(t, len(m.Mock.Calls), 2) + } + ``` +## `template-data` + +| key | type | description | +|-----|------|-------------| +| `unroll-variadic` | `#!yaml bool` | If set to `#!yaml true`, will expand the variadic argument to testify using the `...` syntax. See [notes](./notes.md#variadic-arguments) for more details. | + +## Features + +### Replace Types :octicons-tag-24: v2.23.0 @@ -147,129 +331,7 @@ type InternalBaz struct{} func (*InternalBaz) Foo() *baz.Baz {} ``` -`packages` configuration ------------------------- -:octicons-tag-24: v2.21.0 - -!!! info - See the [Migration Docs](migrating_to_packages.md) on how to migrate to this new feature. - -Mockery has a configuration parameter called `packages`. In this config section, you define the packages and the interfaces you want mocks generated for. The packages can be any arbitrary package, either your own project or anything within the Go ecosystem. You may provide package-level or interface-level overrides to the default config you provide. - -Usage of the `packages` config section is desirable for multiple reasons: - -1. Up to 5x increase in mock generation speed over the legacy method -2. Granular control over interface generation, location, and file names -3. Singular location for all config, instead of spread around by `//go:generate` statements -4. Clean, easy to understand. - -### Examples - -Here is an example configuration set: - -```yaml -with-expecter: True -packages: - github.com/vektra/mockery/v3/pkg: # (1)! - interfaces: - TypesPackage: - RequesterVariadic: - config: # (2)! - with-expecter: False - configs: - - mockname: MockRequesterVariadicOneArgument - unroll-variadic: False - - mockname: MockRequesterVariadic - io: - config: - all: True # (3)! - interfaces: - Writer: - config: - with-expecter: False # (4)! -``` - -1. For this package, we provide no package-level config (which means we inherit the defaults at the top-level). Since our default of `all:` is `False`, mockery will only generate the interfaces we specify. We tell it which interface to generate by using the `interfaces` section and specifying an empty map, one for each interface. -2. There might be cases where you want multiple mocks generated from the same interface. To do this, you can define a default `config` section for the interface, and further `configs` (plural) section, one for each mock. You _must_ specify a `mockname` for the mocks in this section to differentiate them. -3. This is telling mockery to generate _all_ interfaces in the `io` package. -4. We can provide interface-specific overrides to the generation config. - -### Templated variables - -!!! note - Templated variables are only available when using the `packages` config feature. - -Included with this feature is the ability to use templated strings for various configuration options. This is useful to define where your mocks are placed and how to name them. You can view the template variables available in the [Configuration](configuration.md#template-variables) section of the docs. - -### Recursive package discovery - -:octicons-tag-24: v2.25.0 - -When `#!yaml recursive: true` is set on a particular package: - -```yaml -packages: - github.com/user/project: - config: - recursive: true - with-expecter: true -``` - -mockery will dynamically discover all sub-packages within the specified package. This is done by calling `packages.Load` on the specified package, which induces Go to download the package from the internet (or simply your local project). Mockery then recursively discovers all sub-directories from the root package that also contain `.go` files and injects the respective package path into the config map as if you had specified them manually. As an example, your in-memory config map may end up looking like this: - -```yaml -packages: - github.com/user/project: - config: - recursive: true - with-expecter: true - github.com/user/project/subpkg1: - config: - recursive: true - with-expecter: true - github.com/user/project/subpkg2: - config: - recursive: true - with-expecter: true -``` - -You can use the `showconfig` command to see the config mockery injects. The output of `showconfig` theoretically could be copy-pasted into your YAML file as it is semantically equivalent. - -mockery will _not_ recurse into submodules, i.e. any subdirectory that contains a go.mod file. You must specify the submodule as a separate line item in the config if you would like mocks generated for it as well. - -??? note "performance characteristics" - The performance when using `#!yaml recursive: true` may be worse than manually specifying all packages statically in the YAML file. This is because of the fact that mockery has to recursively walk the filesystem path that contains the package in question. It may unnecessarily walk down unrelated paths (for example, a Python virtual environment that is in the same path as your package). For this reason, it is recommended _not_ to use `#!yaml recursive: true` if it can be avoided. - -### Regex matching - -You can filter matched interfaces using the `include-regex` option. To generate mocks only for interfaces ending in `Client` we can use the following configuration: - -```yaml -packages: - github.com/user/project: - config: - recursive: true - include-regex: ".*Client" -``` - -To further refine matched interfaces, you can also use `exclude-regex`. If an interface matches both `include-regex` and `exclude-regex` then it will not be generated. For example, to generate all interfaces except those ending in `Func`: - -```yaml -packages: - github.com/user/project: - config: - recursive: true - include-regex: ".*" - exclude-regex: ".*Func" -``` - -You can only use `exclude-regex` with `include-regex`. If set by itself, `exclude-regex` has no effect. - -??? note "all: true" - Using `all: true` will override `include-regex` (and `exclude-regex`) and issue a warning. - -Mock Constructors ------------------ +### Mock Constructors :octicons-tag-24: v2.11.0 @@ -293,8 +355,7 @@ The constructor sets up common functionalities automatically - The testing.TB interface is registered on the `mock.Mock` so that tests don't panic when a call on the mock is unexpected. -Expecter Structs ----------------- +### Expecter Structs :octicons-tag-24: v2.10.0 ยท `with-expecter: True` @@ -318,19 +379,18 @@ A `RunAndReturn` method is also available on the expecter struct that allows you ```go requesterMock.EXPECT(). Get(mock.Anything). - RunAndReturn(func(path string) (string, error) { + RunAndReturn(func(path string) (string, error) { fmt.Println(path, "was called") return ("result for " + path), nil }) ``` -!!! note +!!! note Note that the types of the arguments on the `EXPECT` methods are `interface{}`, not the actual type of your interface. The reason for this is that you may want to pass `mock.Any` as an argument, which means that the argument you pass may be an arbitrary type. The types are still provided in the expecter method docstrings. -Return Value Providers ----------------------- +### Return Value Providers :octicons-tag-24: v2.20.0 @@ -338,7 +398,7 @@ Return Value Providers can be used one of two ways. You may either define a sing ```go type Proxy interface { -passthrough(ctx context.Context, s string) (string, error) + passthrough(ctx context.Context, s string) (string, error) } ``` diff --git a/docs/template-moq.md b/docs/template-moq.md new file mode 100644 index 00000000..32aef71c --- /dev/null +++ b/docs/template-moq.md @@ -0,0 +1,125 @@ +--- +title: Moq +--- + +Moq +==== + + +## Description + +=== "Interface" + + ```go + package test + + type Requester interface { + Get(path string) (string, error) + } + ``` + +=== "`.mockery.yml`" + + ```yaml + template: moq + packages: + github.com/vektra/mockery/v3/pkg/fixtures: + config: + dir: "{{.InterfaceDir}}" + filename: "mocks_moq.go" + pkgname: "test" + mockname: "Moq{{.InterfaceName}}" + interfaces: + Requester: + ``` + +=== "`mocks_moq.go`" + + ```go + // Code generated by mockery; DO NOT EDIT. + // github.com/vektra/mockery + + package test + + import ( + "sync" + ) + + // Ensure, that MoqRequester does implement Requester. + // If this is not the case, regenerate this file with moq. + var _ Requester = &MoqRequester{} + + // MoqRequester is a mock implementation of Requester. + // + // func TestSomethingThatUsesRequester(t *testing.T) { + // + // // make and configure a mocked Requester + // mockedRequester := &MoqRequester{ + // GetFunc: func(path string) (string, error) { + // panic("mock out the Get method") + // }, + // } + // + // // use mockedRequester in code that requires Requester + // // and then make assertions. + // + // } + type MoqRequester struct { + // GetFunc mocks the Get method. + GetFunc func(path string) (string, error) + + // calls tracks calls to the methods. + calls struct { + // Get holds details about calls to the Get method. + Get []struct { + // Path is the path argument value. + Path string + } + } + lockGet sync.RWMutex + } + + // Get calls GetFunc. + func (mock *MoqRequester) Get(path string) (string, error) { + // ... + } + + // GetCalls gets all the calls that were made to Get. + // Check the length with: + // + // len(mockedRequester.GetCalls()) + func (mock *MoqRequester) GetCalls() []struct { + Path string + } { + // ... + } + + ``` + +=== "Example Usage" + + ```go + func TestRequesterMoq(t *testing.T) { + m := &MoqRequester{ + GetFunc: func(path string) (string, error) { + fmt.Printf("Go path: %s\n", path) + return path + "/foo", nil + }, + } + result, err := m.Get("/path") + assert.NoError(t, err) + assert.Equal(t, "/path/foo", result) + } + ``` + +Moq-style mocks are far simpler, and probably more intuitive, than mockery-style mocks. All that's needed is to define the function that will be run when the mock's method is called. + +## `template-data` + +`moq` accepts the following `#!yaml template-data:` keys: + +| key | type | description | +|-----|------|-------------| +| `skip-ensure` | `#!yaml bool` | Suppress mock implementation check, avoid import cycle if mocks generated outside of the tested package. | +| `stub-impl` | `#!yaml bool` | Return zero values when no mock implementation is provided, do not panic. | +| `with-resets` | `#!yaml bool` | Generates methods that allow resetting calls made to the mocks. | \ No newline at end of file diff --git a/docs/templates.md b/docs/templates.md index 9858f208..095ed77a 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -8,301 +8,45 @@ templates that you can select with the `#!yaml template:` config parameter. ### `#!yaml template: "mockery"` -Choosing this template will render a traditional "mockery-style" template. The -section below shows what will be rendered for the given interface. +[`mockery`](template-mockery.md) templates generate powerful, testify-based mock objects. They allow you to create expectations using argument-to-return-value matching logic. -=== "Interface" +```go +package test - ```go - package test +import ( + "testing" - type Requester interface { - Get(path string) (string, error) - } - ``` - -=== "`.mockery.yml`" - - ```yaml - template: mockery - packages: - github.com/vektra/mockery/v3/pkg/fixtures: - config: - dir: "{{.InterfaceDir}}" - filename: "mocks.go" - pkgname: "test" - mockname: "Mock{{.InterfaceName}}" - interfaces: - Requester: - ``` - -=== "`mocks.go`" - - ```go - // Code generated by mockery; DO NOT EDIT. - // github.com/vektra/mockery - - package test - - import ( - mock "github.com/stretchr/testify/mock" - ) - - - // NewRequester creates a new instance of Requester. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. - // The first argument is typically a *testing.T value. - func NewRequester (t interface { - mock.TestingT - Cleanup(func()) - }) *Requester { - // ... - } - - - // Requester is an autogenerated mock type for the Requester type - type Requester struct { - mock.Mock - } - - type Requester_Expecter struct { - mock *mock.Mock - } - - func (_m *Requester) EXPECT() *Requester_Expecter { - // ... - } - - - - // Get provides a mock function for the type Requester - func (_mock *Requester) Get(path string) (string, error) { - // ... - } - - - - // Requester_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' - type Requester_Get_Call struct { - *mock.Call - } - - - - // Get is a helper method to define mock.On call - // - path - func (_e *Requester_Expecter) Get(path interface{}, ) *Requester_Get_Call { - // ... - } - - func (_c *Requester_Get_Call) Run(run func(path string)) *Requester_Get_Call { - // ... - } - - func (_c *Requester_Get_Call) Return(s string, err error) *Requester_Get_Call { - // ... - } - - func (_c *Requester_Get_Call) RunAndReturn(run func(path string)(string, error)) *Requester_Get_Call { - // ... - } - ``` - -=== "Example Usage" - - ```go - package test - - import ( - "testing" - - "github.com/stretchr/testify/assert" - ) - - func TestRequesterMock(t *testing.T) { - m := NewMockRequester(t) - m.EXPECT().Get("foo").Return("bar", nil).Once() - retString, err := m.Get("foo") - assert.NoError(t, err) - assert.Equal(t, retString, "bar") - } - ``` - -As you can see, this mock utilizes `github.com/stretchr/testify` under the hood and registers call expectations with testify. When the mock receives a call to `Get()`, it retrieves the expected value from testify to be returned. - -This style of mock also has other interesting methods: - -=== "`#!go Run()`" - - Run a side effect when the argument matches. - - ```go - func TestRequesterMockRun(t *testing.T) { - m := NewMockRequester(t) - m.EXPECT().Get(mock.Anything).Return("", nil) - m.EXPECT().Get(mock.Anything).Run(func(path string) { - fmt.Printf("Side effect! Argument is: %s", path) - }) - retString, err := m.Get("hello") - assert.NoError(t, err) - assert.Equal(t, retString, "") - } - ``` - -=== "`#!go RunAndReturn()`" - - Run a function to perform side-effects, and return the result of the function. - - ```go - func TestRequesterMockRunAndReturn(t *testing.T) { - m := NewMockRequester(t) - m.EXPECT().Get(mock.Anything).RunAndReturn(func(path string) (string, error) { - return path + " world", nil - }) - retString, err := m.Get("hello") - assert.NoError(t, err) - assert.Equal(t, retString, "hello world") - } - ``` - -=== "`github.com/stretchr/testify/mock.Mock`" - - Because the mock embeds the testify `Mock` object, you can all any methods on that as well. - - ```go - func TestRequesterMockTestifyEmbed(t *testing.T) { - m := NewMockRequester(t) - m.EXPECT().Get(mock.Anything).Return("", nil).Twice() - m.Get("hello") - m.Get("world") - assert.Equal(t, len(m.Mock.Calls), 2) - } - ``` -#### `template-data` + "github.com/stretchr/testify/assert" +) -| key | type | description | -|-----|------|-------------| -| `unroll-variadic` | `#!yaml bool` | If set to `#!yaml true`, will expand the variadic argument to testify using the `...` syntax. See [notes](./notes.md#variadic-arguments) for more details. | +func TestRequesterMock(t *testing.T) { + m := NewMockRequester(t) + m.EXPECT().Get("foo").Return("bar", nil).Once() + retString, err := m.Get("foo") + assert.NoError(t, err) + assert.Equal(t, retString, "bar") +} +``` ### `#!yaml template: "moq"` -`moq` templates draw from the mocks generated from the project at https://github.com/matryer/moq. This project was folded into mockery, and thus moq-style mocks can be natively generated from within mockery. - - -=== "Interface" - - ```go - package test - - type Requester interface { - Get(path string) (string, error) - } - ``` - -=== "`.mockery.yml`" - - ```yaml - template: moq - packages: - github.com/vektra/mockery/v3/pkg/fixtures: - config: - dir: "{{.InterfaceDir}}" - filename: "mocks_moq.go" - pkgname: "test" - mockname: "Moq{{.InterfaceName}}" - interfaces: - Requester: - ``` - -=== "`mocks_moq.go`" - - ```go - // Code generated by mockery; DO NOT EDIT. - // github.com/vektra/mockery - - package test - - import ( - "sync" - ) - - // Ensure, that MoqRequester does implement Requester. - // If this is not the case, regenerate this file with moq. - var _ Requester = &MoqRequester{} - - // MoqRequester is a mock implementation of Requester. - // - // func TestSomethingThatUsesRequester(t *testing.T) { - // - // // make and configure a mocked Requester - // mockedRequester := &MoqRequester{ - // GetFunc: func(path string) (string, error) { - // panic("mock out the Get method") - // }, - // } - // - // // use mockedRequester in code that requires Requester - // // and then make assertions. - // - // } - type MoqRequester struct { - // GetFunc mocks the Get method. - GetFunc func(path string) (string, error) - - // calls tracks calls to the methods. - calls struct { - // Get holds details about calls to the Get method. - Get []struct { - // Path is the path argument value. - Path string - } - } - lockGet sync.RWMutex - } - - // Get calls GetFunc. - func (mock *MoqRequester) Get(path string) (string, error) { - // ... - } - - // GetCalls gets all the calls that were made to Get. - // Check the length with: - // - // len(mockedRequester.GetCalls()) - func (mock *MoqRequester) GetCalls() []struct { - Path string - } { - // ... - } - - ``` +[`moq`](template-moq.md) templates draw from the mocks generated from the project at https://github.com/matryer/moq. This project was folded into mockery, and thus moq-style mocks can be natively generated from within mockery. -=== "Example Usage" +Mocks generated using this template allow you to define precise functions to be run. Example: - ```go - func TestRequesterMoq(t *testing.T) { - m := &MoqRequester{ - GetFunc: func(path string) (string, error) { - fmt.Printf("Go path: %s\n", path) - return path + "/foo", nil - }, - } - result, err := m.Get("/path") - assert.NoError(t, err) - assert.Equal(t, "/path/foo", result) +```go +func TestRequesterMoq(t *testing.T) { + m := &MoqRequester{ + GetFunc: func(path string) (string, error) { + fmt.Printf("Go path: %s\n", path) + return path + "/foo", nil + }, } - ``` - -Moq-style mocks are far simpler, and probably more intuitive, than mockery-style mocks. All that's needed is to define the function that will be run when the mock's method is called. - -#### `template-data` - -`moq` accepts the following `#!yaml template-data:` keys: - -| key | type | description | -|-----|------|-------------| -| `skip-ensure` | `#!yaml bool` | Suppress mock implementation check, avoid import cycle if mocks generated outside of the tested package. | -| `stub-impl` | `#!yaml bool` | Return zero values when no mock implementation is provided, do not panic. | -| `with-resets` | `#!yaml bool` | Generates methods that allow resetting calls made to the mocks. | + result, err := m.Get("/path") + assert.NoError(t, err) + assert.Equal(t, "/path/foo", result) +} +``` ### `#!yaml template: "file://` @@ -314,9 +58,11 @@ Mockery has two separate template instances: one for the `.mockery.yml` file, an ### `.mockery.yml` +As seen in the [configuration](configuration.md) section, mockery configuration has template variables and methods available to it. + #### Functions -As seen in the [configuration](configuration.md) section, mockery configuration has template variables and methods available to it. The functions available for use are defined in the [`StringManipulationFuncs`](https://pkg.go.dev/github.com/vektra/mockery/v3/template#pkg-variables). +Functions provided are in the [`StringManipulationFuncs`](https://pkg.go.dev/github.com/vektra/mockery/v3/template#pkg-variables) variable. #### Variables @@ -331,4 +77,4 @@ Template files have both [`StringManipulationFuncs`](https://pkg.go.dev/github.c #### Variables -The template is supplied with the [`template.Data`](https://pkg.go.dev/github.com/vektra/mockery/v3/template#Data) struct. Some attributes return types such as [`template.MockData`](https://pkg.go.dev/github.com/vektra/mockery/v3@v3.0.0-alpha.10/template#MockData) and [`registry.Package`](https://pkg.go.dev/github.com/vektra/mockery/v3/registry#Package) which themselves contain methods that may also be called. +The template is supplied with the [`template.Data`](https://pkg.go.dev/github.com/vektra/mockery/v3/template#Data) struct. Some attributes return types such as [`template.MockData`](https://pkg.go.dev/github.com/vektra/mockery/v3@v3.0.0-alpha.10/template#MockData) and [`template.Package`](https://pkg.go.dev/github.com/vektra/mockery/v3/template#Package) which themselves contain methods that may also be called. diff --git a/mkdocs.yml b/mkdocs.yml index 9915ca57..1636659f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -62,10 +62,11 @@ nav: - Configuration: configuration.md - Templates: templates.md - Running: running.md - - Examples: examples.md - - Features: features.md + - Templates: + - template-mockery.md + - template-moq.md - Notes: - - FAQ: notes.md + - FAQ: faq.md extra_css: - stylesheets/extra.css diff --git a/template/README.md b/template/README.md new file mode 100644 index 00000000..fcf857b0 --- /dev/null +++ b/template/README.md @@ -0,0 +1,4 @@ +Mockery Templates +----------------- + +Further documentation for this project can be found on https://vektra.github.io/mockery/v3/. \ No newline at end of file