Verify - Software Engineering

Inline test helpers

Use inline test helpers to minimize indentation and have failures point out failed cases directly. Given a function calculating the double of an int.

// double returns the double of i if i is positive but never more than
// max int
func double(i int) (int, error) {
	if i < 0 {
		return 0, fmt.Errorf("double: i must be positive")
	}
	n := i * 2
	if n < i {
		return MAX, nil
	}
	return n, nil
}

const MAX int = int(^uint(0) >> 1)

The test would look like this.

Inlined helper does not need t argument.
Descriptive cases fail on correct line.
func Test_double(t *testing.T) {
	ok := func(input, exp int) {
		t.Helper()
		got, err := double(input)
		if err != nil {
			t.Error(err)
		}
		if got != exp {
			t.Errorf("double(%v) returned %v, expected %v", input, got, exp)
		}
	}
	// cases
	ok(1, 2)
	ok(3, 6)
	ok(MAX, MAX)

	bad := func(input, exp int) {
		t.Helper()
		_, err := double(input)
		if err == nil {
			t.Errorf("double(%v) should fail", input)
		}
	}
	bad(-2, 4)
}
Utmost 2 inlined helpers.

Keep it simple and use utmost two inlined helpers. Compared to table-driven-tests inlined helpers declare the how before the cases. If you have many cases, this style is more readable as you first tell the reader the meaning of "ok" and "bad".
Another positive benefit of this style is values are not grouped in a testcase variable. I.e. readability improves as the values are used directly.
This style may be less readable if each case requires many values, though it depends on the lenght of the values combined.