Top Related Projects
Quick Overview
Counterfeiter is a tool for generating test doubles in Go. It automatically creates fake implementations of interfaces, which can be used in unit tests to mock dependencies and control their behavior. This tool simplifies the process of writing and maintaining test code in Go projects.
Pros
- Automatically generates mock implementations, saving time and reducing boilerplate code
- Supports both interfaces and function types
- Integrates well with Go's testing framework
- Provides a simple CLI for easy usage
Cons
- Requires regeneration of mocks when interfaces change
- May lead to over-reliance on mocks in testing, potentially missing integration issues
- Learning curve for developers new to mocking or the tool's specific syntax
- Generated code can be verbose and increase the overall codebase size
Code Examples
- Generating a mock for an interface:
//go:generate counterfeiter -o fake_reader.go . Reader
type Reader interface {
Read(p []byte) (n int, err error)
}
- Using a generated mock in a test:
import (
"testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"path/to/fakes"
)
var _ = Describe("Using a mock", func() {
It("should call the mocked method", func() {
fake := &fakes.FakeReader{}
fake.ReadReturns(5, nil)
buffer := make([]byte, 10)
n, err := fake.Read(buffer)
Expect(n).To(Equal(5))
Expect(err).To(BeNil())
Expect(fake.ReadCallCount()).To(Equal(1))
})
})
- Stubbing multiple return values:
fake := &fakes.FakeReader{}
fake.ReadReturnsOnCall(0, 5, nil)
fake.ReadReturnsOnCall(1, 0, io.EOF)
buffer := make([]byte, 10)
n, err := fake.Read(buffer)
// First call returns 5, nil
n, err = fake.Read(buffer)
// Second call returns 0, io.EOF
Getting Started
-
Install Counterfeiter:
go install github.com/maxbrunsfeld/counterfeiter/v6@latest
-
Add a generate comment to your interface file:
//go:generate counterfeiter -o fake_myinterface.go . MyInterface type MyInterface interface { // ... interface methods ... }
-
Run go generate:
go generate ./...
-
Use the generated fake in your tests:
fake := &fakes.FakeMyInterface{} // Configure and use the fake as needed in your tests
Competitor Comparisons
GoMock is a mocking framework for the Go programming language.
Pros of mock
- Part of the official Go project, ensuring long-term maintenance and compatibility
- Supports generating mocks for interfaces from external packages
- Offers more advanced features like call ordering expectations
Cons of mock
- Requires writing boilerplate code for each mock
- Less intuitive API for setting up expectations and assertions
- Steeper learning curve for beginners
Code Comparison
mock:
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockObj := NewMockInterface(ctrl)
mockObj.EXPECT().SomeMethod(gomock.Any()).Return(42)
counterfeiter:
fake := new(InterfaceFake)
fake.SomeMethodReturns(42)
Summary
While mock offers more advanced features and is part of the official Go project, counterfeiter provides a simpler API and requires less boilerplate code. mock is better suited for complex mocking scenarios, while counterfeiter is more user-friendly for beginners and simpler use cases. The choice between the two depends on the specific project requirements and the team's familiarity with each tool.
A mock code autogenerator for Go
Pros of Mockery
- Supports mocking of interfaces, structs, and functions
- Provides a more extensive set of assertion methods
- Offers better integration with popular testing frameworks like testify
Cons of Mockery
- Requires more setup and boilerplate code
- Learning curve can be steeper for beginners
- May have slightly slower performance in some cases
Code Comparison
Mockery:
mock := new(mocks.MyInterface)
mock.On("MyMethod", 1, "test").Return(true, nil)
result, err := mock.MyMethod(1, "test")
mock.AssertExpectations(t)
Counterfeiter:
fake := new(fakes.FakeMyInterface)
fake.MyMethodReturns(true, nil)
result, err := fake.MyMethod(1, "test")
Expect(fake.MyMethodCallCount()).To(Equal(1))
Both Mockery and Counterfeiter are popular mocking libraries for Go, each with its own strengths. Mockery offers more flexibility and features, while Counterfeiter provides a simpler API and easier setup. The choice between them often depends on project requirements and personal preference.
A toolkit with common assertions and mocks that plays nicely with the standard library
Pros of testify
- Broader testing toolkit with assertions, mocks, and suites
- More active development and community support
- Extensive documentation and examples
Cons of testify
- Steeper learning curve due to more features
- Potentially more complex setup for simple test cases
Code Comparison
testify:
assert := assert.New(t)
assert.Equal(expected, actual, "they should be equal")
mock := new(MyMockedObject)
mock.On("DoSomething", 123).Return(true, nil)
counterfeiter:
fake := new(CounterfeiterFakes.FakeInterface)
fake.SomeMethodReturns("result", nil)
Expect(fake.SomeMethod()).To(Equal("result"))
Key Differences
- testify provides a more comprehensive testing framework
- counterfeiter focuses specifically on generating test doubles
- testify uses assertion-style syntax, while counterfeiter integrates with Ginkgo/Gomega
Use Cases
- testify: Suitable for projects requiring a full-featured testing toolkit
- counterfeiter: Ideal for projects needing efficient mock generation, especially with complex interfaces
Community and Ecosystem
- testify: Larger community, more third-party integrations
- counterfeiter: Smaller but dedicated user base, often used in conjunction with other testing tools
Monkey patching in Go
Pros of Monkey
- Allows patching of unexported functions and methods
- Supports patching of built-in Go types
- Simpler API for quick mocking and stubbing
Cons of Monkey
- Uses unsafe runtime patching, which can be risky
- May not work with all Go versions or in all environments
- Limited to function/method replacement, not full interface mocking
Code Comparison
Monkey:
patch := monkey.Patch(fmt.Println, func(a ...interface{}) (n int, err error) {
return 0, nil
})
defer patch.Unpatch()
Counterfeiter:
type FakePrinter struct {
PrintlnStub func(a ...interface{}) (n int, err error)
printlnMutex sync.RWMutex
printlnArgsForCall [][]interface{}
}
Summary
Monkey offers a simpler API for quick mocking and supports patching unexported and built-in functions. However, it uses unsafe runtime patching, which can be risky. Counterfeiter generates full mock implementations of interfaces, providing more comprehensive testing capabilities but requires more setup. Choose based on your specific testing needs and risk tolerance.
HTTP mocking for Golang
Pros of httpmock
- Specifically designed for mocking HTTP responses, making it more focused and potentially easier to use for HTTP-related testing
- Provides a simple and intuitive API for setting up mock HTTP responses
- Supports both Go's built-in
http.Client
and popular third-party HTTP clients
Cons of httpmock
- Limited to HTTP mocking, whereas Counterfeiter can generate mocks for any interface
- May require more setup for complex HTTP scenarios compared to Counterfeiter's generated mocks
- Less flexibility in terms of customizing mock behavior beyond HTTP responses
Code Comparison
httpmock:
httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder("GET", "https://api.example.com/users",
httpmock.NewStringResponder(200, `[{"id": 1, "name": "John"}]`))
Counterfeiter:
//go:generate counterfeiter . UserService
type UserService interface {
GetUsers() ([]User, error)
}
fakeUserService := new(UserServicefakes.FakeUserService)
fakeUserService.GetUsersReturns([]User{{ID: 1, Name: "John"}}, nil)
Both libraries serve different purposes, with httpmock focusing on HTTP mocking and Counterfeiter providing a more general-purpose mocking solution for interfaces. The choice between them depends on the specific testing requirements of your project.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
counterfeiter
When writing unit-tests for an object, it is often useful to have fake implementations of the object's collaborators. In go, such fake implementations cannot be generated automatically at runtime, and writing them by hand can be quite arduous.
counterfeiter
allows you to simply generate test doubles for a given interface.
Supported Versions Of go
counterfeiter
follows the support policy of go
itself:
Each major Go release is supported until there are two newer major releases. For example, Go 1.5 was supported until the Go 1.7 release, and Go 1.6 was supported until the Go 1.8 release. We fix critical problems, including critical security problems, in supported releases as needed by issuing minor revisions (for example, Go 1.6.1, Go 1.6.2, and so on).
If you are having problems with counterfeiter
and are not using a supported version of go, please update to use a supported version of go before opening an issue.
Using counterfeiter
â ï¸ Please use go modules
when working with counterfeiter.
Typically, counterfeiter
is used in go generate
directives. It can be frustrating when you change your interface declaration and suddenly all of your generated code is suddenly out-of-date. The best practice here is to use the go generate
command to make it easier to keep your test doubles up to date.
Step 1 - Create tools.go
You can take a dependency on tools by creating a tools.go
file, as described in How can I track tool dependencies for a module?. This ensures that everyone working with your module is using the same version of each tool you use.
$ cat tools/tools.go
//go:build tools
package tools
import (
_ "github.com/maxbrunsfeld/counterfeiter/v6"
)
// This file imports packages that are used when running go generate, or used
// during the development process but not otherwise depended on by built code.
Step 2a - Add go:generate
Directives
You can add directives right next to your interface definitions (or not), in any .go
file in your module.
$ cat myinterface.go
package foo
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . MySpecialInterface
type MySpecialInterface interface {
DoThings(string, uint64) (int, error)
}
$ go generate ./...
Writing `FakeMySpecialInterface` to `foofakes/fake_my_special_interface.go`... Done
Step 2b - Add counterfeiter:generate
Directives
If you plan to have many directives in a single package, consider using this
option. You can add directives right next to your interface definitions
(or not), in any .go
file in your module.
$ cat myinterface.go
package foo
// You only need **one** of these per package!
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -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)
}
$ go generate ./...
Writing `FakeMySpecialInterface` to `foofakes/fake_my_special_interface.go`... Done
Writing `FakeMyOtherInterface` to `foofakes/fake_my_other_interface.go`... Done
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):
$ go generate ./...
Invoking counterfeiter
from the shell
You can use the following command to invoke counterfeiter
from within a go module:
$ go run github.com/maxbrunsfeld/counterfeiter/v6
USAGE
counterfeiter
[-generate>] [-o <output-path>] [-p] [--fake-name <fake-name>]
[-header <header-file>]
[<source-path>] <interface> [-]
Installing counterfeiter
to $GOPATH/bin
This is unnecessary if you're using the approach described above, but does allow you to invoke counterfeiter
in your shell outside of a module:
$ go install github.com/maxbrunsfeld/counterfeiter/v6
$ ~/go/bin/counterfeiter
USAGE
counterfeiter
[-generate>] [-o <output-path>] [-p] [--fake-name <fake-name>]
[-header <header-file>]
[<source-path>] <interface> [-]
Generating Test Doubles
Given a path to a package and an interface name, you can generate a test double.
$ cat path/to/foo/file.go
package foo
type MySpecialInterface interface {
DoThings(string, uint64) (int, error)
}
$ go run github.com/maxbrunsfeld/counterfeiter/v6 path/to/foo MySpecialInterface
Wrote `FakeMySpecialInterface` to `path/to/foo/foofakes/fake_my_special_interface.go`
Using Test Doubles In Your Tests
Instantiate fakes:
import "my-repo/path/to/foo/foofakes"
var fake = &foofakes.FakeMySpecialInterface{}
Fakes record the arguments they were called with:
fake.DoThings("stuff", 5)
Expect(fake.DoThingsCallCount()).To(Equal(1))
str, num := fake.DoThingsArgsForCall(0)
Expect(str).To(Equal("stuff"))
Expect(num).To(Equal(uint64(5)))
You can stub their return values:
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")))
For more examples of using the counterfeiter
API, look at some of the provided examples.
Generating Test Doubles For Third Party Interfaces
For third party interfaces, you can specify the interface using the alternative syntax <package>.<interface>
, for example:
$ go run github.com/maxbrunsfeld/counterfeiter/v6 github.com/go-redis/redis.Pipeliner
Running The Tests For counterfeiter
If you want to run the tests for counterfeiter
(perhaps, because you want to contribute a PR), all you have to do is run scripts/ci.sh
.
Contributions
So you want to contribute to counterfeiter
! That's great, here's exactly what you should do:
- open a new github issue, describing your problem, or use case
- help us understand how you want to fix or extend
counterfeiter
- write one or more unit tests for the behavior you want
- write the simplest code you can for the feature you're working on
- try to find any opportunities to refactor
- avoid writing code that isn't covered by unit tests
counterfeiter
has a few high level goals for contributors to keep in mind
- keep unit-level test coverage as high as possible
- keep
main.go
as simple as possible - avoid making the command line options any more complicated
- avoid making the internals of
counterfeiter
any more complicated
If you have any questions about how to contribute, rest assured that @tjarratt and other maintainers will work with you to ensure we make counterfeiter
better, together. This project has largely been maintained by the community, and we greatly appreciate any PR (whether big or small).
License
counterfeiter
is MIT-licensed.
Top Related Projects
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot