---
title: B. Fakes
---

## What are Fakes?

**Fakes** are a useful tool for unit testing.
They can intelligently mimic the behavior of the underlying interface that you are stubbing out,
and they keep track of state for you so that you can assert your expectations following test completion.

**Mocks** are similar to Fakes, but (typically) have several downsides:
- Mocks do not keep track of their internal state, and so cannot simulate state-dependent client behavior.
(Note that some mocking libraries such as Vektra/Mockery do in fact keep track of some state for you).
- Mocks require you to manually stub out a response for every call you expect to happen during a unit test,
whereas Fakes have default behavior hardcoded (for example, always returning 'nil').

We use [Counterfeiter](https://github.com/maxbrunsfeld/counterfeiter) to generate Fakes.
We prefer **Counterfeiter** to its notable Golang alternative [Mockery](https://github.com/vektra/mockery) for the following reasons:
- Counterfeiter has correctly typed arguments (meaning IDE syntax benefits)
- Counterfeiter has compile-time type checking (your test won’t build vs mockery telling you a vague error during runtime)
- Counterfeiter generation is faster than Mockery

## Using Fakes

For these examples, we will assume we have a simple client with one method:

```go
type DB interface {
    // GetItem gets a single item by its ID.
    GetItem(context.Context, string) (string, error)
}
```

### Basic Usage

The most basic usage of a Fake.
Here we force the fake implementation to return an error to create a unit test covering that case.

```go
package client_test

import (
    "errors"

    "internal/client"
    "internal/fakes"
)

func TestGetItem(t *testing.T) {
    t.Run("DB returns error", func(t *testing.T) {
        var fakeDB = &fakes.FakeDB{}
    
        c := &client.Client{
            DB: fakeDB,
        }
    
        fakeDB.GetReturns("", errors.New("err"))
    
        resp, err := c.GetItem(context.Background, "testid")
        if resp != "" {
            t.Errorf("expected resp='' but instead = '%s'", resp)
        }
        if err == nil {
            t.Errorf("expected err != nil")
        }
    })
    
    t.Run("DB returns error", func(t *testing.T) {
        var fakeDB = &fakes.FakeDB{}
    
        c := &client.Client{
            DB: fakeDB,
        }
    
        fakeDB.GetReturns("hello", nil)
    
        resp, err := c.GetItem(context.Background, "testid")
        if resp != "hello" {
            t.Errorf("expected resp='hello' but instead = '%s'", resp)
        }
        if err != nil {
            t.Errorf("expected err == nil but instead got %s", err)
        }
    })
}
```

### Advanced Usage

#### Asserting arguments and number of calls

To guarantee correctness, it is often good to assert the number of times your fakes were called.

```go
if fakeDB.GetItemCallCount() != 1 {
    t.Errorf("expected GetItem to be called exactly once")
}

// We don't typically care about validating the context argument.
_, id := fakeDB.GetItemArgsForCall(0) // 0-indexed
if id != "hello"" {
    t.Errorf("expected id to be 'hello', instead was %s", id)
}
```

#### Stubs

Stubs are what you might typically think of when you imagine a "fake" implementation.
While Counterfeiter provides helpers for stubbing out return values via `*Returns()`,
and differing return values depending on call index using `*ReturnsOnCall()`,
you may want to implement more complex behavior depending on the input or on saved external state.

```go
// We set the GetItemStub field equal to a function matching the signature of the faked method.
fakeDB.GetItemStub = func(ctx context.Context, id string) (string, error) {
    if id == "id1" {
        return "this is the data for id1"
    } else if id == "id2" {
        return "this is the data for id2"
    }
    return "", errors.New("not found")
}
```

Here we implement a DB that fails every other GetItem request:
```go
var callCount = 0
fakeDB.GetItemStub = func(ctx context.Context, id string) (string, error) {
    defer callCount++
    if callCount%2 == 1 {
        return "", errors.New("err")
    }
    return "hello", nil
}
```
