Chapter 14 - Automated Testing

Exercise 1: Testing a Package

Here is code for an ordinals package, with an Ordinal function that converts the integer 1 to the string 1st, 2 to 2nd, and so on. We have intentionally left out the code that converts 3 to 3rd, so that we have a case where tests should fail.

You can either create this file manually, or install it automatically with:

$ go get github.com/jaymcgavren/ordinals

$GOPATH/src/github.com/jaymcgavren/ordinals/ordinals.go

// Package ordinals converts integers to ordinal numbers.
// 1: 1st, 2: 2nd, and so on.
package ordinals

import "fmt"

// Ordinal accepts an integer and returns a string with
// that integer's ordinal form.
func Ordinal(number int) string {
	lastDigit := number % 10
	isInTeens := (number%100)/10 == 1
	if isInTeens {
		return fmt.Sprintf("%dth", number)
	} else if lastDigit == 1 {
		return fmt.Sprintf("%dst", number)
	} else if lastDigit == 2 {
		return fmt.Sprintf("%dnd", number)
	} else {
		return fmt.Sprintf("%dth", number)
	}
}

Your goal is to create automated tests with the following expectations:

Ordinal Parameter Expected Return Value
1 "1st"
2 "2nd"
3 "3rd" (this test should fail)
4 "4th"
11 "11th"
21 "21st"

 

For now, you can use a failure message of "didn't match expected value" for every test.

Output:

$ go test github.com/jaymcgavren/ordinals
--- FAIL: TestThree (0.00s)
	ordinals_test.go:19: didn't match expected value
FAIL
FAIL	github.com/jaymcgavren/ordinals	0.006s

When you’re ready, have a look at our solution.

Exercise 2: Test Helper Methods

Write a helper function for your tests that accepts these parameters:

  • The argument passed to Ordinal.
  • The actual return value from Ordinal.
  • The expected return value.

It should return a string in this format (without square brackets):

Ordinal([input]) = "[actual]", want "[expected]"

Update your tests for the calls Ordinal(1), Ordinal(2), and Ordinal(3) to use this helper function.

Output:

$ go test github.com/jaymcgavren/ordinals
--- FAIL: TestThree (0.00s)
	ordinals_test.go:31: Ordinal(3) = "3th", want "3rd"
FAIL
FAIL	github.com/jaymcgavren/ordinals	0.007s

Here’s our solution.

Exercise 3: Table-Driven Tests

Replace all your tests with a table-driven test:

  • Create a testData type with fields for the argument to pass to Ordinal and the return value you want.
  • Create a slice of testData values representing the various arguments you want to pass and the return values you expect to see.
  • Loop over each testData value in the slice:
    • Pass the argument field from the testData to Ordinal, and record the return value you got.
    • If the return value you got doesn’t match the expected return value field from the testData, call t.Errorf.
    • Use the same format for the test failure string that you used for your helper function from the previous exercise. (Once you’re done, the helper function will be redundant, so you can delete it.)

Output:

$ go test github.com/jaymcgavren/ordinals
--- FAIL: TestThree (0.00s)
	ordinals_test.go:31: Ordinal(3) = "3th", want "3rd"
FAIL
FAIL	github.com/jaymcgavren/ordinals	0.007s

Here’s our solution.

Play around! We encourage you to try changing the code in Ordinal to fix the broken test or to intentionally break other tests, and to add tests for additional arguments. You can also try creating your own package from scratch, and write tests for all its functions!