Skip to content
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

Open
wants to merge 54 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
e06c157
Internal registry for disambiguated imports, vars (#141)
sudo-suhas Feb 1, 2021
36a85ce
feat: support generic interface generation (#175)
cgorenflo Oct 1, 2022
d1b2fd4
Go version independent moq output with consistent whitespace
sudo-suhas Nov 13, 2022
d411b15
Add flag to enable mock reset methods (#181)
cbaker Mar 8, 2023
0028a34
updates
LandonTClipp Oct 19, 2023
d16ef1b
Internal registry for disambiguated imports, vars (#141)
sudo-suhas Feb 1, 2021
5ea7cda
Fix var name generation to avoid conflict (#145)
sudo-suhas Feb 14, 2021
2c9d05c
Ignore anonymous imports when resolving import aliases (#150)
maneac Jul 4, 2021
9e0e5d0
Fix issue with custom types shadowing basic types (#163)
dedalusj Dec 18, 2021
92a6e93
Added packages.NeedDeps bit to packages.LoadMode to fix error (#171)
metalrex100 Mar 29, 2022
4468afa
feat: support generic interface generation (#175)
cgorenflo Oct 1, 2022
fb12cf9
Recursively check unique pkg names against existing imports
sudo-suhas Nov 13, 2022
ebe7652
Add imports for Named Type's type arguments (#199)
TimVosch Jun 21, 2023
222a8a9
Do not load unnecessary package information (#203)
samherrmann Aug 13, 2023
1d04e7d
Add registry package from moq
LandonTClipp Oct 19, 2023
e68ee26
updates
LandonTClipp Oct 19, 2023
3eb17fe
updates
LandonTClipp Oct 19, 2023
860c2c8
updates
LandonTClipp Oct 20, 2023
d66be2c
Add more code to plumb through all the values needed by moq registry …
LandonTClipp Nov 20, 2023
1edd82f
Successfully created first moq
LandonTClipp Dec 23, 2023
f19f1f1
add config for moq
LandonTClipp Dec 23, 2023
852b19e
add formatter back
LandonTClipp Dec 23, 2023
9d89443
fix
LandonTClipp Dec 23, 2023
9aa5b53
change moq.templ comment
LandonTClipp Feb 12, 2024
1f078dc
Merge branch 'master' into moq
LandonTClipp Feb 12, 2024
e3fe47c
fix formatting issue with master merge
LandonTClipp Feb 12, 2024
62ef480
Add generics plumbing through moq
LandonTClipp Feb 12, 2024
5d37c18
update mocks with new features
LandonTClipp Feb 12, 2024
f9bee27
Move generator to separate package
LandonTClipp Feb 13, 2024
2ded465
Add moq configuration to Taskfile
LandonTClipp Feb 13, 2024
f144fb5
fix config
LandonTClipp Feb 13, 2024
4a1905b
Add mocks for moq
LandonTClipp Feb 13, 2024
d25b5da
fix config
LandonTClipp Feb 13, 2024
63653e0
fix taskfile
LandonTClipp Feb 13, 2024
a0f012b
Split out warn logs to logging package
LandonTClipp Feb 13, 2024
19b9718
Add template-map config param.
LandonTClipp Feb 13, 2024
db5f5a6
check err of generateMockery
LandonTClipp Feb 13, 2024
05f2c4d
update moq mocks
LandonTClipp Feb 13, 2024
587f197
update docs and moq config
LandonTClipp Feb 13, 2024
1805cf2
fix tests
LandonTClipp Feb 13, 2024
0aa59fb
Merge branch 'master' into moq
LandonTClipp Feb 13, 2024
cdd540b
Fix issue with ordering of filesystem walk
LandonTClipp Feb 13, 2024
ddf4a43
Merge branch 'moq' of github.com:LandonTClipp/mockery into moq
LandonTClipp Feb 13, 2024
7f4d02d
fix to go.mod logic
LandonTClipp Feb 13, 2024
78eb414
Add context.Context to more moq functions for logging
LandonTClipp Feb 21, 2024
f0de03c
Change name of moq mocks
LandonTClipp Feb 21, 2024
a82b265
Fix moq generation when inpackage=True
LandonTClipp Feb 21, 2024
a9aac88
Fix issue with registry not importing original package
LandonTClipp Feb 21, 2024
f57f7b1
update moqs
LandonTClipp Feb 21, 2024
dd61c0f
Merge branch 'master' into moq
LandonTClipp Feb 21, 2024
c8a2304
change codecov threshold to 0
LandonTClipp Feb 21, 2024
37562c5
updates
LandonTClipp Feb 21, 2024
4ddd30b
reduce codecov patch requirement to 0
LandonTClipp Feb 21, 2024
8ff0a85
fix codecov project target
LandonTClipp Feb 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 23 additions & 0 deletions .mockery-moq.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
quiet: False
disable-version-string: True
mockname: "{{.InterfaceName}}Moq"
filename: "{{.InterfaceName | snakecase }}_moq.go"
dir: "mocks/moq/{{.PackagePath}}"
style: moq
packages:
github.com/vektra/mockery/v2/pkg/fixtures:
config:
include-regex: '.*'
exclude-regex: 'RequesterGenerics|UnsafeInterface|requester_unexported'
outpkg: test
template-map:
with-resets: true
skip-ensure: false
stub-impl: false
inpackage: false
github.com/vektra/mockery/v2/pkg/fixtures/inpackage:
config:
dir: "{{.InterfaceDir}}"
all: True
outpkg: "{{.PackageName}}"
inpackage: true
1 change: 0 additions & 1 deletion .mockery.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ packages:
unroll-variadic: False
- mockname: Expecter
unroll-variadic: True
RequesterReturnElided:
VariadicNoReturnInterface:
config:
with-expecter: True
Expand Down
3 changes: 2 additions & 1 deletion Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ tasks:
mocks.remove:
desc: remove all mock files
cmds:
- find . -name '*_mock.go' | xargs rm
- find . -name '*_mock.go' -o -name '*_moq.go' | xargs rm
- rm -rf mocks/

mocks.generate:
desc: generate mockery mocks
cmds:
- go run .
- go run . --config .mockery-moq.yaml

docker:
desc: build the mockery docker image
Expand Down
41 changes: 10 additions & 31 deletions cmd/mockery.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

"github.com/chigopher/pathlib"
"github.com/mitchellh/go-homedir"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
Expand Down Expand Up @@ -83,6 +82,7 @@
pFlags.Bool("exported", false, "Generates public mocks for private interfaces.")
pFlags.Bool("with-expecter", false, "Generate expecter utility around mock's On, Run and Return methods with explicit types. This option is NOT compatible with -unroll-variadic=false")
pFlags.StringArray("replace-type", nil, "Replace types")
pFlags.String("style", "", "select which mock style to use")

if err := viperCfg.BindPFlags(pFlags); err != nil {
panic(fmt.Sprintf("failed to bind PFlags: %v", err))
Expand Down Expand Up @@ -212,10 +212,6 @@
return nil
}

var osp pkg.OutputStreamProvider
if r.Config.Print {
osp = &pkg.StdoutStreamProvider{}
}
buildTags := strings.Split(r.Config.BuildTags, " ")

var boilerplate string
Expand All @@ -238,7 +234,7 @@
if err != nil {
return fmt.Errorf("failed to get package from config: %w", err)
}
parser := pkg.NewParser(buildTags)
parser := pkg.NewParser(buildTags, pkg.ParserSkipFunctions(false))

if err := parser.ParsePackages(ctx, configuredPackages); err != nil {
log.Error().Err(err).Msg("unable to parse packages")
Expand All @@ -259,7 +255,7 @@

ifaceCtx := ifaceLog.WithContext(ctx)

shouldGenerate, err := r.Config.ShouldGenerateInterface(ifaceCtx, iface.QualifiedName, iface.Name)
shouldGenerate, err := r.Config.ShouldGenerateInterface(ifaceCtx, iface.QualifiedName, iface.Name, iface.IsFunction)
if err != nil {
return err
}
Expand All @@ -269,7 +265,7 @@
}
ifaceLog.Debug().Msg("config specifies to generate this interface")

outputter := pkg.NewOutputter(&r.Config, boilerplate, true)
outputter := pkg.NewOutputter(&r.Config, boilerplate)
if err := outputter.Generate(ifaceCtx, iface); err != nil {
return err
}
Expand All @@ -278,6 +274,11 @@
return nil
}

var osp pkg.OutputStreamProvider
if r.Config.Print {
osp = &pkg.StdoutStreamProvider{}
}

Check warning on line 280 in cmd/mockery.go

View check run for this annotation

Codecov / codecov/patch

cmd/mockery.go#L279-L280

Added lines #L279 - L280 were not covered by tests

if r.Config.Name != "" && r.Config.All {
log.Fatal().Msgf("Specify --name or --all, but not both")
} else if (r.Config.FileName != "" || r.Config.StructName != "") && r.Config.All {
Expand All @@ -303,7 +304,7 @@
log.Fatal().Msgf("Use --name to specify the name of the interface or --all for all interfaces found")
}

warnDeprecated(
logging.WarnDeprecated(
ctx,
"use of the packages config will be the only way to generate mocks in v3. Please migrate your config to use the packages feature.",
map[string]any{
Expand Down Expand Up @@ -395,25 +396,3 @@

return nil
}

func warn(ctx context.Context, prefix string, message string, fields map[string]any) {
log := zerolog.Ctx(ctx)
event := log.Warn()
if fields != nil {
event = event.Fields(fields)
}
event.Msgf("%s: %s", prefix, message)
}

func info(ctx context.Context, prefix string, message string, fields map[string]any) {
log := zerolog.Ctx(ctx)
event := log.Info()
if fields != nil {
event = event.Fields(fields)
}
event.Msgf("%s: %s", prefix, message)
}

func warnDeprecated(ctx context.Context, message string, fields map[string]any) {
warn(ctx, "DEPRECATION", message, fields)
}
10 changes: 7 additions & 3 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
coverage:
precision: 5
round: down
range: "40...100"
range: "0...100"
status:
patch:
default:
target: 40%
target: 0%
threshold: 35%
base: auto
project:
default:
target: 0%
threshold: 35%
base: auto

5 changes: 3 additions & 2 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,15 @@ Parameter Descriptions
| `include-regex` | :fontawesome-solid-x: | `#!yaml ""` | When set, only interface names that match the expression will be generated. This setting is ignored if `all: True` is specified in the configuration. To further refine the interfaces generated, use `exclude-regex`. |
| `inpackage` | :fontawesome-solid-x: | `#!yaml false` | When generating mocks alongside the original interfaces, you must specify `inpackage: True` to inform mockery that the mock is being placed in the same package as the original interface. |
| `log-level` | :fontawesome-solid-x: | `#!yaml "info"` | Set the level of the logger |
| `mock-build-tags` | :fontawesome-solid-x: | `#!yaml ""` | Set the build tags of the generated mocks. Read more about the [format](https://pkg.go.dev/cmd/go#hdr-Build_constraints). |
| `mock-build-tags` | :fontawesome-solid-x: | `#!yaml ""` | Set the build tags of the generated mocks. Read more about the [format](https://pkg.go.dev/cmd/go#hdr-Build_constraints). |
| `mockname` | :fontawesome-solid-check: | `#!yaml "Mock{{.InterfaceName}}"` | The name of the generated mock. |
| `outpkg` | :fontawesome-solid-check: | `#!yaml "{{.PackageName}}"` | Use `outpkg` to specify the package name of the generated mocks. |
| [`packages`](features.md#packages-configuration) | :fontawesome-solid-x: | `#!yaml null` | A dictionary containing configuration describing the packages and interfaces to generate mocks for. |
| `print` | :fontawesome-solid-x: | `#!yaml false` | Use `print: True` to have the resulting code printed out instead of written to disk. |
| [`recursive`](features.md#recursive-package-discovery) | :fontawesome-solid-x: | `#!yaml false` | When set to `true` on a particular package, mockery will recursively search for all sub-packages and inject those packages into the config map. |
| [`replace-type`](features.md#replace-types) | :fontawesome-solid-x: | `#!yaml null` | Replaces aliases, packages and/or types during generation. |
| `tags` | :fontawesome-solid-x: | `#!yaml ""` | A space-separated list of additional build tags to load packages. |
| [`style`](/mockery/features/#mock-styles) | :fontawesome-solid-x: | `#!yaml mockery` | Set the style of mocks to generate. |
| `tags` | :fontawesome-solid-x: | `#!yaml ""` | A space-separated list of additional build tags to load packages. |
| [`with-expecter`](features.md#expecter-structs) | :fontawesome-solid-x: | `#!yaml true` | Use `with-expecter: True` to generate `EXPECT()` methods for your mocks. This is the preferred way to setup your mocks. |

Layouts
Expand Down
117 changes: 117 additions & 0 deletions docs/features.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,123 @@
Features
========

Mock Styles
------------

:octicons-tag-24: v2.42.0 :material-test-tube:{ .tooltip foo }

!!! warning "ALPHA"
This feature is currently in alpha. Usage is not recommended for production applications as the configuration semantics and/or mock behavior might change in future releases.

mockery provides a parameter called `#!yaml style:` that allows you to specify different styles of mock implementations. This parameter defaults to `#!yaml style: mockery`, but you may also provide other values described below:

| style | description |
|-------|-------------|
| `mockery` | The default style. Generates the mocks that you typically expect from this project. |
| `moq` | Generates mocks in the style of [Mat Ryer's project](https://github.com/matryer/moq). |

This table describes the characteristics of each mock style.

| feature | `mockery` | `moq` |
|---------|-----------|-------|
| Uses testify | :white_check_mark: | :x: |
| Strictly typed arguments | :warning:[^1] | :white_check_mark: |
| Stricly typed return values | :white_check_mark: | :white_check_mark: |
| Multiple mocks per file | :x: | :x: |
| Return values mapped from argument values | :white_check_mark: | :x: |
| Supports generics | :white_check_mark: | :white_check_mark: |
|

[^1]:
If you use the `.RunAndReturn` method in the [`.EXPECT()`](/mockery/features/#expecter-structs) structs, you can get strict type safety. Otherwise, `.EXPECT()` methods are type-safe-ish, meaning you'll get compiler errors if you have the incorrect number of arguments, but the types of the arguments themselves are `interface{}` due to the need to specify `mock.Anything` in some cases.

### `mockery`

`mockery` is the default style of mocks you are used to with this project.

### `moq`

The `moq` implementations are generated using similar logic as the project at https://github.com/matryer/moq. The mocks rely on you defining stub functions that will be called directly from each method. For example, assume you have an interface like this:

```go
type Requester interface {
Get(path string) (string, error)
}
```

`moq` will create an implementation that looks roughly like this:

```go
type RequesterMock 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 *RequesterMock) Get(path string) (string, error) {
if mock.GetFunc == nil {
panic("RequesterMock.GetFunc: method is nil but Requester.Get was just called")
}
callInfo := struct {
Path string
}{
Path: path,
}
mock.lockGet.Lock()
mock.calls.Get = append(mock.calls.Get, callInfo)
mock.lockGet.Unlock()
return mock.GetFunc(path)
}
```

The way you interact with this mock in a test would look like this:

```go
func TestRequester(t *testing.T){
requesterMock := &RequesterMock{
GetFunc: func(path string) (string, error) {
return "value", fmt.Errorf("failed")
}
}
}
```

#### Configuration

A simple basic configuration might look like this:

```yaml
style: moq
packages:
github.com/vektra/mockery/v2/pkg/fixtures:
config:
template-map:
with-resets: true
skip-ensure: true
stub-impl: false
```

The `moq` style is driven entirely off of Go templates. Various features of the moq may be toggled by using the `#! template-map:` mapping. These are the moq-specific parameters:

| name | default | description |
|------|---------|-------------|
| `#!yaml with-resets` | `<no value>` | Generates functions that aid in resetting the list of calls made to a mock. |
| `#!yaml skip-ensure` | `<no value>` | Skips adding a compile-time check that asserts the generated mock properly implements the interface. |
| `#!yaml stub-impl` | `<no value>` | Sets methods to return the zero value when no mock implementation is provided. |

!!! note
Many of the parameters listed in the [parameter descriptions page](/mockery/configuration/#parameter-descriptions) also apply to `moq`. However, some parameters of `mockery`-styled mocks will not apply to `moq`. Efforts will be made to ensure the documentation is clear on which parameters apply to which style.

Replace Types
-------------

Expand Down
4 changes: 3 additions & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
mike @ git+https://github.com/jimporter/mike.git
mkdocs
mkdocs-glightbox
git+https://${GH_TOKEN}@github.com/squidfunk/mkdocs-material-insiders.git
# replace the below mkdocs-material line below with "mkdocs-material"
# if you don't have access to the insiders edition.
git+https://${GH_TOKEN}@github.com/squidfunk/mkdocs-material-insiders.git@9.5.5-insiders-4.51.0
mkdocs-open-in-new-tab
cairosvg
pillow
3 changes: 2 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@ theme:
- content.code.copy
- content.action.edit
- content.action.view
- content.footnote.tooltips
- navigation.indexes
- navigation.sections
- navigation.tracking
- toc.follow
markdown_extensions:
- admonition
- attr_list
- footnotes
- md_in_html
- pymdownx.emoji:
emoji_index: !!python/name:material.extensions.emoji.twemoji
Expand All @@ -53,7 +55,6 @@ markdown_extensions:
alternate_style: true
- toc:
permalink: true


nav:
- Home: index.md
Expand Down