counterfeiter is a command-line tool for generating fake implementation of Go interfaces.

One of the best things we can do when writing Go programs is to design our components’ dependencies to be based on local interfaces. By local I mean interfaces which are needed and defined by a given component. Consider the following example: we have a http server, a service component and a database dependency.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
package main

func main() {
	// initialize some kind of database
	db := storage.New()
	
	// our service depends on a database
	svc := service.New(db)
	
	http.HandleFunc("/example", svc.Example)
	log.Fatal(http.ListenAndServe(":8080", nil))
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
package storage

type DB struct {}

type Data struct {}

func New() *DB {
	return &DB{}
}

func (db *DB) SomeData() (*Data, error) {
	... // return data from database
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package service

type Storage interface {
	SomeData() (*storage.Data, error)
}

type Data struct{
	Value int
}

type Service struct {
	db Storage
}

func New(db Storage) *Service {
	return &Service{db:db}
}

func (s *Service) Example(w http.ResponseWriter, r *http.Request) {
	// do something that requires using the database
	data, err := s.db.SomeData()
	if err != nil {
		...
	}

	// do something with data and write response
	...
}

The service component has a database dependency. It may be any kind of external object - client to another service, a cache/database, message queue, whatever. This dependency is expressed as an interface inside the service package. In effect, the service is telling its initialiser: when you create me, please give me an object which implements my service.Storage interface, cause that’s what I need to execute my functions.

This design has some nice benefits. The service component doesn’t know and care how the storage dependency is implemented. All it knows and cares about is that it has a SomeData() (*storage.Data, error) function. We can supply whatever object we wish to the service, as long as it implements the interface.

Here comes the counterfeiter

A common use case for using dependency interfaces, is that we can write service component unit tests with 100% coverage, by using a fake implementation of the service.Storage interface.

counterfeiter generates fake implementations for interfaces. To generate a fake implementation for service.Storage, we add a go:generate directive in the service package.

1
2
3
4
5
6
7
8
package service

//go:generate counterfeiter . Storage

Storage interface {
	SomeData() (*Data, error)
}
...

Another way is to manually run from terminal in the service folder the counterfeiter . Storage command.

1
2
$ counterfeiter . Storage
Writing `FakeStorage` to `servicefakes/fake_storage.go`... Done

After the command is executed, it creates a fake folder with FakeStorage implementation of the service.Storage interface. When writing unit tests, we would initialise our service component with the fake object and manipulate its API to cover all code branches and use of the database dependency.

Checkout the counterfeiter docs for more info and examples.