Convert Figma logo to code with AI

maxbrunsfeld logocounterfeiter

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

1,009
95
1,009
27

Top Related Projects

9,329

GoMock is a mocking framework for the Go programming language.

6,214

A mock code autogenerator for Go

23,648

A toolkit with common assertions and mocks that plays nicely with the standard library

3,364

Monkey patching in Go

HTTP mocking for Golang

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

  1. Generating a mock for an interface:
//go:generate counterfeiter -o fake_reader.go . Reader
type Reader interface {
    Read(p []byte) (n int, err error)
}
  1. 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))
    })
})
  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

  1. Install Counterfeiter:

    go install github.com/maxbrunsfeld/counterfeiter/v6@latest
    
  2. Add a generate comment to your interface file:

    //go:generate counterfeiter -o fake_myinterface.go . MyInterface
    type MyInterface interface {
        // ... interface methods ...
    }
    
  3. Run go generate:

    go generate ./...
    
  4. Use the generated fake in your tests:

    fake := &fakes.FakeMyInterface{}
    // Configure and use the fake as needed in your tests
    

Competitor Comparisons

9,329

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.

6,214

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.

23,648

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
3,364

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 Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

counterfeiter GitHub Actions Go Report Card GoDoc

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.