Baike.dev
All toolsOnline toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
C

counterfeiter

> 编程语言
Open source

A tool for generating self-contained, type-safe test doubles in go

1.1K stars0 likes1 views
WebsiteGitHub

About

A tool for generating self-contained, type-safe test doubles in go

counterfeiter

Go code declares what it needs from its dependencies as interfaces, usually small ones defined by the package that uses them. Testing that code means supplying fake implementations of those interfaces. Go has no way to build one at runtime, so they are written by hand or generated.

counterfeiter generates test doubles for a given interface. Given this:

go
package foo

//go:generate go tool counterfeiter -generate

//counterfeiter:generate . MySpecialInterface
type MySpecialInterface interface {
	DoThings(string, uint64) (int, error)
}

go generate writes foofakes/fake_my_special_interface.go, and your tests can do this:

go
fake := &foofakes.FakeMySpecialInterface{}
fake.DoThingsReturns(3, nil)

num, err := fake.DoThings("stuff", 5)

Expect(num).To(Equal(3))
Expect(fake.DoThingsCallCount()).To(Equal(1))
str, _ := fake.DoThingsArgsForCall(0)
Expect(str).To(Equal("stuff"))

Getting Started

counterfeiter is run by go generate, so fakes are regenerated alongside the code they fake. The steps below assume go 1.24 or later, which added go tool; for older versions of go, refer to an older version of this README.

Step 1 - Add counterfeiter as a tool dependency

Establish a tool dependency on counterfeiter by running the following command:

bash
go get -tool github.com/maxbrunsfeld/counterfeiter/v6

Step 2 - Add directives

Add one go:generate directive per package that runs counterfeiter -generate, and one counterfeiter:generate directive per interface you want a fake for. You can add them right next to your interface definitions (or not), in any .go file in the package.

In myinterface.go:

go
package foo

// You only need **one** of these per package!
//go:generate go tool counterfeiter -generate

// You will add lots of directives like these in the same package...
//counterfeiter:generate . MySpecialInterface
type MySpecialInterface interface {
	DoThings(string, uint64) (int, error)
}

// Like this...
//counterfeiter:generate . MyOtherInterface
type MyOtherInterface interface {
	DoOtherThings(string, uint64) (int, error)
}

A counterfeiter:generate directive takes the same arguments as the command line: the directory of the package that declares the interface (. for the package the directive is in) and the name of the interface, plus any of the flags described below.

If a package only has an interface or two, you can skip -generate and the counterfeiter:generate directives, and run counterfeiter directly from one go:generate line per interface instead:

go
//go:generate go tool counterfeiter . MySpecialInterface

-generate is much faster once there are several directives in a package, because it loads the package once and writes every fake from one process, where each go:generate line starts a new one.

Step 3 - Run go generate

You can run go generate in the directory with your directive, or in the root of your module (to ensure you generate for all packages in your module):

bash
$ go generate ./...
Writing `FakeMySpecialInterface` to `foofakes/fake_my_special_interface.go`... Done
Writing `FakeMyOtherInterface` to `foofakes/fake_my_other_interface.go`... Done

Defaults

MySpecialInterface above is declared in package foo, so //counterfeiter:generate . MySpecialInterface produces:

default change it with
fake type FakeMySpecialInterface (Fake + the interface name) -fake-name, -fake-name-template
file fake_my_special_interface.go (the fake's name in snake case) -o .go
directory foofakes/ (fakes, beside the package that declares the interface) -o
package foofakes (fakes), or whatever package already lives in the output directory -o, -test, or a file declaring the package

Every fake ends with a compile-time assertion that it satisfies the interface, so when the interface changes, the stale fake stops compiling until you run go generate again.

Common Setups

The examples below are counterfeiter:generate directives, and assume the package has the //go:generate go tool counterfeiter -generate line from Step 2. A package needs only one of those, no matter how many directives it has.

Shared settings for every directive in a package

Flags given alongside -generate on the //go:generate line are the defaults for every //counterfeiter:generate directive in the package: -o, -header, -q, -test and -fake-name-template. A directive's own flags take precedence. So if you would rather keep all of a package's fakes in a fake package, named after their interfaces, you can write that once:

go
//go:generate go tool counterfeiter -generate -o fake -fake-name-template '{{.TargetName}}'

//counterfeiter:generate . MyRepository
//counterfeiter:generate . MyPresenter
bash
$ go generate ./...
Writing `MyRepository` to `fake/my_repository.go`... Done
Writing `MyPresenter` to `fake/my_presenter.go`... Done

Interfaces from other packages, the standard library or third-party modules

You can fake any interface your module can import. A third-party module has to be a dependency first (go get it, so it appears in your go.mod), since counterfeiter loads the interface from the module cache the same way the compiler would. Name the interface as ., or give the directory of the package and the interface name:

go
//counterfeiter:generate io.WriteCloser
//counterfeiter:generate github.com/redis/go-redis/v9.Pipeliner
//counterfeiter:generate ../otherpackage OtherInterface

The two forms differ in where the fake goes. With ., it goes into the fakes package of the directory the directive is in, so in package foo the first line writes foofakes/fake_write_closer.go. With a directory and an interface name, it goes into the fakes package beside that directory, so the third line writes ../otherpackage/otherpackagefakes/fake_other_interface.go. Use -o to put it somewhere else.

Fakes for tests inside the interface's own package

By default the fake lives in a sibling fakes package. Tests in itself cannot import it, because `fakes` imports and that would be an import cycle. To use a fake in those tests, point -o at the interface's own directory:

go
//counterfeiter:generate -o . . MySpecialInterface

When the output directory is the directory of the package that declares the interface, counterfeiter generates the fake as a member of that package: it does not import the package, refers to its types unqualified, and can fake unexported interfaces too, in which case the fake is unexported as well (gadget gets fakeGadget) unless -fake-name names it. -o may also name a file in that directory, for example -o fake_my_special_interface_test.go to keep the fake out of the non-test build.

Fakes for tests in _test

Go lets a directory hold a second package for tests, _test, which imports `` and sees only its exported API. If your tests are in it, -test generates the fake into that external test package instead, as a _test.go file in the current directory, next to the tests that use it:

go
//counterfeiter:generate -test . MySpecialInterface
//counterfeiter:generate -test ../otherpackage OtherInterface
//counterfeiter:generate -test io.WriteCloser

In package foo, all three of these write a _test.go file into the current directory, in package foo_test: fake_my_special_interface_test.go, fake_other_interface_test.go and fake_write_closer_test.go. With -test the fake goes into the package the directive is in, not the package that declares the interface, so faking OtherInterface writes nothing into ../otherpackage. The fakes are only compiled for tests, and the tests use them unqualified (&FakeMySpecialInterface{}). The interface's package is imported as usual, so the interface must be exported. With -o the fake goes into the external test package of that directory instead.

A fakes package whose name is not its directory name

If the output directory already contains Go files, the fake joins that package. If it is empty, the fake's package is named after the directory. So to name the package differently from its directory, say impl_fakes in fakes/, add a file declaring that package first:

go
// fakes/doc.go
package impl_fakes
go
//counterfeiter:generate -o fakes . MyInterface

Naming fakes

-fake-name names one fake. -fake-name-template is a Go text/template in which {{.TargetName}} is the name of the interface being faked (first letter upper-cased); it applies wherever -fake-name is not given, and can be set once for the package on the -generate line. The file name follows the fake's name.

go
//counterfeiter:generate -fake-name Repo . MyRepository
//counterfeiter:generate -fake-name-template '{{.TargetName}}Double' . MyPresenter
bash
$ go generate ./...
Writing `Repo` to `foofakes/repo.go`... Done
Writing `MyPresenterDouble` to `foofakes/my_presenter_double.go`... Done

A header on every fake

-header prepends the contents of a file to every generated fake, for a licence header for example. Set it once on the -generate line, or per directive.

go
//go:generate go tool counterfeiter -generate -header ../LICENSE.header

Faking a function type

Function types can be faked as well. The fake is a struct whose Spy method has the function's signature, so fake.Spy goes wherever the function is expected. Returns, CallCount, ArgsForCall and the rest work as for a method, without a method name in front.

go
//counterfeiter:generate . RequestHandler
type RequestHandler func(*http.Request) error
go
fake := &foofakes.FakeRequestHandler{}
fake.Returns(nil)

server := NewServer(fake.Spy)

Faking a whole package

Package mode, -p, is for code that calls package-level functions directly, os.Hostname() say, and has no interface to fake. It writes a file with an interface whose methods are the package's exported functions, and a shim struct that forwards each method to the package. The file carries a counterfeiter:generate directive of its own, so the next go generate produces a fake of that interface.

go
//counterfeiter:generate -p os
bash
$ go generate ./...
Writing `Os` to `osshim/os.go`... Done
$ go generate ./...
Writing `FakeOs` to `osshimfakes/fake_os.go`... Done

Your code takes the osshim.Os interface, production code passes &osshim.OsShim{}, tests pass the fake.

Printing to stdout, quieter output

A trailing - prints the fake to standard output instead of writing a file:

bash
$ go tool counterfeiter . MySpecialInterface -

-q drops the Writing ... lines, which is useful in a -generate line for a package with many fakes.

Using Test Doubles In Your Tests

Instantiate fakes:

go
import "my-repo/path/to/foo/foofakes"

var fake = &foofakes.FakeMySpecialInterface{}

For each method `` of the interface, the fake has:

Returns, ReturnsOnCall stub what it returns
Calls, Stub replace it with a function
CallCount, ArgsForCall inspect the calls it received

You can stub return values:

go
fake.DoThingsReturns(3, errors.New("the-error"))

num, err := fake.DoThings("stuff", 5)
Expect(num).To(Equal(3))
Expect(err).To(Equal(errors.New("the-error")))

or stub them for one call at a time, counting from zero; calls without an entry fall back to Returns:

go
fake.DoThingsReturnsOnCall(0, 1, nil)
fake.DoThingsReturnsOnCall(1, 0, errors.New("the-error"))

When the result depends on t

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

Go

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言