<div class="sidenote">Tests should be correct by inspection</div>
Tests require a different approach than normal code. We don't have
tests for tests, so tests need to be correct by inspection -- and the
main technique to achieve this is to get rid of the generality of the
production code, and exercise only very narrow and specific scenarios.

# Decide what test to write

<div class="sidenote">The goal of testing is to increase confidence</div>
A test's purpose is to increase the confidence that you have in your
program's correctness. The next test to write is the test that
promises the highest ratio of additional confidence for the work
required to write it.

## Do test all your business decisions

Test all your code that is testable. Prioritize testing the code that
(a) **is important to work correctly** (where confidence needs to be
high) or (b) **has become too complicated** (where confidence has
dropped too low).

## Don't test I/O and side effects

<div class="sidenote">Controversial part ahead!</div>
Sometimes, production code will do I/O or other side effects that are
hard to simulate reproducably in a test. In these cases, it can
sometimes be advisable to separate the I/O parts of the production
code out and only test the rest - the bulk of your logic. It's key to
only separate out only the smallest possible part that has the side
effect, to keep as much as possible of the program testable.

"But Günther", I hear you saying, "what if there is a bug in these I/O
parts"? Well - that's why you need to keep them tiny and stare at them
very long in a code review, to make sure they work without a test. It
sounds heretic to leave this untested, but the alternative is to keep
the I/O and other program logic together. That'll easily make your
more regular program logic hard to test, and that's often not worth
the trade off. After all, our goal is to increase confidence, not to
reach full line coverage.

**Special case:** There are also some types of I/O which don't affect
your program logic, such as logging and incrementing performance
counters. It's ok to leave those untested without separating them
out - these are battle proof APIs designed for quickly adding and
removing them from your code, and they do not play a role for your
programs correctness. It would give you little additional confidence
to test them.

# Structure your tests into Given/When/Then

<div class="sidenote">Stick to the three test phases!</div>

Stick with the setup/exercise/verify style of tests. Some people call
this also
[Given/When/Then](https://martinfowler.com/bliki/GivenWhenThen.html)
or the ["Four Phase
test"](http://xunitpatterns.com/Four%20Phase%20Test.html) (counting
tear-down as separate phase).

It does not matter what you call this pattern, but "Given/When/Then"
tends to read nice in comments. Delimiting the section explicitly with
comments is optional, but serves another useful purpose: You cannot
use helper functions that span multiple of these purposes. (Those
helper functions would be bad style.)

```go
func TestSpellOut(t *testing.T) {
  // Given
  s := speller.New("en")

  // When
  got := s.SpellOut(42)

  // Then
  want := "forty-two"
  if got != want {
    t.Errorf("SpellOut(%q); got %q, want %q", 42, got, want)
  }
}
```

# Test helpers

Test helper functions should be the primary way to share functionality
between tests.

<div class="sidenote">Each helper serves only one of the test phases</div>
Make sure that each test helper helps with only one of the test
phases: setup, exercise or verify.

In particular, resist the temptation to extract the whole test into a
helper method, so that you can call it with differing parameters. The
way this is done in Go instead is with [table-driven
tests](https://dave.cheney.net/2019/05/07/prefer-table-driven-tests)
and
[`t.Run()`](https://golang.org/pkg/testing/#hdr-Subtests_and_Sub_benchmarks)
if needed.[^trun]

## Setup helpers

<div class="sidenote">The checklist for setup helpers</div>
A setup helper is called from a test's setup phase and should have the
following properties:

* It accepts a `testing.TB`[^tb] as first parameter.
* It calls `t.Helper()` at the start.
* It may not return an error, but will call `t.Fatal()` on error.
  * It is ok to fail early in setup helpers.
  * Tests don't need to check errors manually, making them easier to read.
* If it sets up state that needs to be undone after the test, it calls
  [`t.Cleanup()`](/post/go-testing-cleanup).

This is a helper method for setting up a `Speller` object from the
previous example:

```go
func setUpSpeller(t testing.TB, path string) speller.Speller {
  t.Helper()

  s, err := speller.Load(path)
  if err != nil {
    t.Fatalf("Could not set up speller: speller.Load(%q): %v",
             path, err)
  }

  t.Cleanup(s.Close)
  return s
}
```

## Exercise helpers

<div class="sidenote">Don't.</div>
Only introduce helpers for the test's execute phase if the invocation
is unbearable to read.

It's good practice to exercise the component under test directly
without such a helper. Using the component directly is a good test for
its API's usability and will often uncover small possibilities for API
improvements in the process.

## Verification helpers

<div class="sidenote">Alternatives to assertion libraries</div>
Common Go style discourages the use of assertion helper libraries,
which are common in most other languages.

While I don't necessarily agree with that, the next best thing you can
do within the bounds of this style is to extract helpers that do the
necessary comparisons for you, if necessary. The ground rule I use is:
The `if` should be part of the top-level test function, but the
condition in that check can call the helper.

* These helpers do not need to have `testing.TB` passed in - they are
  just regular utility functions.
* They should probably return a boolean, or other object representing
  the result of the check (like
  [`cmp.Diff`](https://godoc.org/github.com/google/go-cmp/cmp#Diff))

# General advice on writing tests

A lot of general advice from other testing frameworks is applicable to
Go too.

## Make each test exercise a specific narrow scenario

Each test should exercise a specific and narrow scenario. There should
be little overlap between tests. Any bug introduced in the code should
ideally only break a single test, which has narrow focus and is
related to the broken functionality.

### Start with the assertion

Start writing tests with the assertion, and work from there upwards by
filling out the missing variables that aren't defined yet. This
approach helps me to focus each test around one specific and narrow
behaviour that I want to test.

### One test for the happy path, plus one for each error

With simple functions with inputs, outputs and errors, I like to have
one main test for the happy path, plus one for each error, whose test
input is based on the one for the happy path, with a modification.

See my article on [Shared base fixtures](/post/base_fixture) for examples.

## Avoid `TestMain`, use setup helper functions

If you don't know what `TestMain` is, good!

`TestMain` is a way to share common test setup and teardown between
multiple test cases, without them calling a setup helper explicitly.
In most cases, this is better done with a setup helper function as
described above.

There is one case where `TestMain` is acceptable, which is the case
where the test setup is so expensive to run that it will be
significantly faster to only do it once.

[^tb]: `testing.TB` is an interface for the common methods in
    `testing.T` and `testing.B`, so it can be used from tests and
    benchmarks alike.
[^trun]: `t.Run()` is a way of structuring your test output, but it'll
    also make sure that subtests can cancel with `t.Fatal()`, without
    affecting the execution of other subtests.
