CLI tool
matryer/moq avatar
matryer/moq

Moq: generating Go mocks that read like handwritten test doubles

Interface mocking tool for go generate

2,204 stars139 forksGoMIT

At a glance

What is it?
A small code generator that turns an interface into a struct with a function field per method, designed to be wired into go generate so the mock never drifts out of date.
Who is it for?
Moq's bet is that a generated mock should be as boring to read as a struct you wrote yourself, and the README backs that up with a flag list that has grown deliberately rather than by accretion. Each flag answers a specific complaint: -rm for stale output, -skip-ensure for import cycles, -stub for tests that do not care about a return value, -with-resets for shared fixtures.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 9 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • matryer/moq2,204 ★ · -2
Star history
Repository2026-10-082026-10-23
matryer/moq2.2k2.2k

-2 Stars in the last 15 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

One struct per interface, one function field per method

The README defines the tool in two sentences. Moq is a tool that generates a struct from any interface, and that struct can be used in test code as a mock of the interface. That is the entire contract, and everything else in the project is a consequence of it.

The consequence worth dwelling on is the shape of the generated code. Moq creates a struct that has a function field for each method, which you declare in your test code. The mocked structure implements the interface, where each method calls the associated function field. So instead of a framework with expectations and matchers, you get a struct literal assigning closures, and the compiler checks the rest.

The example in the README is a signup flow. The test declares a `sentTo` string, builds an `EmailSenderMock` with a `SendFunc` that records the recipient and returns nil, calls `CompleteSignUp`, then asserts on `len(mockedEmailSender.SendCalls())` and on the captured value.

go
func TestCompleteSignup(t *testing.T) {

var sentTo string

mockedEmailSender = &EmailSenderMock{
SendFunc: func(to, subject, body string) error {
sentTo = to
return nil
},
}

What stands out is how little machinery is involved. There is no base type to embed with unfamiliar methods, no expectation object to declare, no matcher language. The struct literal is the setup and the call count is the assertion, both using plain Go that a reader can follow without documentation.

Wiring it into go generate so the mock cannot rot

Installation is one command, and the README is explicit that you want the latest released version:

bash
$ go install github.com/matryer/moq@latest

The command line form takes a source directory followed by one or more interface names, and the README flags a detail that catches people out. `source-dir` is the directory where the source code definition of the target interface is located, and it needs to be a path to a directory and not the import statement for a Go package.

bash
$ moq -out mocks_test.go . MyInterface

The reason to reach for `go generate` instead of running that by hand is drift. Every interface change then requires editing a file that nobody wants to edit, and forgetting to do it produces a compile error at best and a stale mock at worst. The in-code form puts the invocation next to the interface itself.

go
package my

//go:generate moq -out myinterface_moq_test.go . MyInterface

The tips section closes with that instruction restated as a practice item: use `go:generate` to invoke the `moq` command. Naming the mock is supported too, through a format of interface:alias, with the example `moq -pkg different . MyInterface:MyMock`. That matters more than it looks, because when a package holds several mocks you want the generated file to carry a distinct package name rather than colliding with the package under test.

Every flag answers a complaint someone actually had

The flag list in the README is short enough to read in full, and each entry reads like a response to a real situation rather than a feature checkbox.

`-fmt` selects the go pretty-printer and accepts gofmt, goimports, or noop, defaulting to gofmt. `-out` names the output file and defaults to stdout. `-pkg` sets the package name, which will otherwise be inferred. `-rm` first removes the output file if it exists, which prevents the failure mode where gofmt or a write error leaves a half-written mock in place. `-skip-ensure` suppresses the mock implementation check and is the flag to reach for when the generated file lands outside the tested package and you would otherwise create an import cycle. `-stub` returns zero values when no mock implementation is provided and does not panic, which is what you want for a test that does not care about a particular return. `-with-resets` generates functions to facilitate resetting calls made to a mock. `-version` prints the version.

Two of these interact in a way the tips explain. The tips say a mock will panic if a nil function gets called, which is the default behaviour and a reasonable choice because a silent zero value in a test that forgot to stub a method hides a real problem. `-stub` is the escape hatch for the cases where you genuinely do not care. The default being loud and the opt-in being quiet is the right way round.

There is also a debugging tip worth keeping. If Moq fails with a `go/format` error, the generated code was not valid, and running the same command with `-fmt noop` prints the generated source without attempting to format it, which aids in finding the root cause. That is a small diagnostic affordance that most generators skip.

Call tracking, resets, and the habits the tips ask for

Beyond generating a struct, Moq maintains call history, and the tips section is really a short style guide for using it.

Use `.MethodCalls()` to track the calls. Use `.ResetCalls()` to reset calls within an individual mock's context. Use closured variables inside your test function to capture details about the calls to the methods. Name arguments in the interface for a better experience. Keep mocked logic inside the test that is using it. Only mock the fields you need.

Each of those is small, but together they describe a testing style. Naming arguments in the interface is the one that pays off longest, because generated method signatures and call trackers become readable in test failures once the parameters have names. Keeping logic inside the test that uses it is the opposite of the shared-fixture approach, and the reset flag exists to make per-mock isolation practical when a fixture does need sharing.

There is a small tension in the tips, or at least a sequencing question. `.ResetCalls()` is listed as a general tip, while the flag list says `-with-resets` is what generates functions to facilitate resetting calls made to a mock. So reset support appears to be opt-in at generation time rather than always present, and if you reach for `ResetCalls()` and find it missing, the flag list is where the answer is. The same applies to the shared fixture story more generally.

The design also means the generated file is ordinary Go. It has no build tag hiding it, no reflection, and no registration step. A reviewer reading a diff on a generated mock can skim it, and when a test breaks, the stack trace goes through a normal struct method rather than through a framework layer.

Where the stated Go version and the module requirement disagree

Here is the contradiction worth pausing on, because it is the kind of thing that turns into a wasted afternoon.

The install section says to note that Go 1.18+ is needed for installing from source, and for using Moq with older Go versions it points at the pre-built binaries published with Moq releases. Read on its own, that sentence describes a tool with a broad compatibility floor and an escape hatch for anyone behind.

The module says something narrower. `go.mod` declares the module as github.com/matryer/moq with a go directive of 1.26, depending only on go-difflib and golang.org/x/tools. The release history agrees with the module rather than the README: v0.6.0, published in August 2025, is titled build with go 1.25, and v0.7.0, published in March 2026, is titled Update go to 1.26, contributed by a first-time contributor through a pull request. v0.7.1 followed the same day.

Both facts are current in the repository. The README states 1.18 or newer for installing from source; the module requires 1.26 and two of the three visible releases exist specifically to move that number up. The practical reading is that the README sentence describes when the install mechanism became possible, while the module describes what the current code actually needs to build. If you are on an older toolchain, the pre-built binaries in the releases section are the path the README itself points to, and you should pick the release that matches your Go version rather than expecting 1.18 to work.

Project shape, provenance, and how it compares to the alternatives

The repository is small and the layout follows the standard split. `main.go` holds the entry point, `generate/` and `internal/` hold the generator logic, `pkg/` the public surface, and `example/` a worked example. There is a `.goreleaser.yml` for publishing pre-built binaries, which is what backs the older Go escape hatch, and a `releasing.md` documenting how a maintainer cuts a version. The project is MIT licensed, is not archived, was last pushed in late August 2026, and sits at roughly 2,200 stars, 136 forks, and 31 open issues.

Provenance is documented with unusual honesty. The README credits Moq as created by Mat Ryer and David Hernandez, with ideas lovingly stolen from Ernesto Jimenez, a major refactor by sudo-suhas, and lots of other contributors. The logo is by Chris Ryer under a Creative Commons Attribution 3.0 license, separate from the MIT license covering the code.

That last credit is the most interesting, because Jimenez wrote mockery, and mockery is one of the tools moq is most often compared against. Search interest around this project splits into several camps: gomock, minimock, mockery, testify's mock package. What separates moq from gomock and mockery in practice is that moq produces plain Go you can read and edit, with no expectation DSL to learn and no runtime dependency. Where gomock's controller model earns its keep is automatic call verification across a whole test, and where mockery earns its keep is configuration and generator flexibility. Moq's position is closer to the handwritten mock you would have written anyway, except that it is regenerated for you.

The comparison question that comes up most often in search results is the difference between mockery and gomock, which is a real question but one that does not mention moq at all. Readers arriving through that search usually want a lightweight, readable mock and end up here by accident. That is worth knowing when you evaluate whether this is the tool you were looking for.

Editorial conclusion

Moq's bet is that a generated mock should be as boring to read as a struct you wrote yourself, and the README backs that up with a flag list that has grown deliberately rather than by accretion. Each flag answers a specific complaint: -rm for stale output, -skip-ensure for import cycles, -stub for tests that do not care about a return value, -with-resets for shared fixtures. The generated code is plain Go with function fields and call trackers, so there is no runtime reflection and no DSL to learn. The one thing worth checking before you commit to it is the Go version question, because the README says 1.18 or newer while the module itself declares go 1.26 and the recent releases are Go version bumps. Install the current release, point a `go:generate` line at your interface, and read the output once to confirm the shape suits how your tests are written.

Frequently asked questions

What is Moq and what does it generate?

Moq is a tool that generates a struct from any Go interface, usable in test code as a mock of that interface. The generated struct has a function field for each method, so you assign closures in a struct literal rather than declaring expectations in a separate DSL.

How do I install Moq and generate my first mock?

Run go install github.com/matryer/moq@latest, then invoke it with a source directory and interface name, for example moq -out mocks_test.go . MyInterface. The source-dir argument must be a directory path, not a Go package import statement.

Which Go version does Moq need?

The README says Go 1.18 or newer is needed for installing from source and points older toolchains at the pre-built binaries in the releases section. The module itself declares go 1.26, and releases v0.6.0 and v0.7.0 exist specifically to move that requirement to 1.25 and then 1.26.

How do I avoid an import cycle when generating mocks?

Pass -skip-ensure, which the README describes as suppressing the mock implementation check to avoid an import cycle when mocks are generated outside of the tested package. You can also use the interface:alias format, for example moq -pkg different . MyInterface:MyMock.

Why does my mock panic when I did not set a function field?

That is the default behaviour, and the tips list it as a feature: a mock panics if a nil function gets called, so a forgotten stub surfaces instead of quietly returning a zero value. Use the -stub flag if a test genuinely does not care about a particular return value.

How do I see how many times a mocked method was called?

Use the generated MethodCalls function, such as SendCalls() in the README example, and read its length. The tips also suggest capturing details with closured variables in the test, and using ResetCalls to clear history within an individual mock, which -with-resets generates.

Official sources

  1. License: MIT
  2. matryer/moq on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/matryer-moq.svg)](https://hysenlabs.com/projects/matryer-moq)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/matryer-moq.svg)](https://hysenlabs.com/projects/matryer-moq)

Was this useful?