GO / CHAPTER 11

Tests, invariants, and boundary cases

Advanced

Choose checks that can distinguish a correct algorithm from a plausible one.

By the end of this chapter

  • Design table-driven cases
  • Assert mutation contracts
  • Test algebraic and boundary properties

The idea

A useful test targets an observable promise. Table-driven tests collect inputs and expected results so normal, boundary, and invalid cases are easy to compare. Give each case a descriptive name and include the empty case when the function supports it. A test that repeats the implementation’s logic can repeat its bug, so derive the expectation directly from the specification.

Some properties cover many concrete inputs. Sorting should preserve length and the multiset of values while producing nondecreasing order. A nonmutating function should leave its input unchanged even if the returned result is modified later. These are distinct assertions: correct output alone cannot establish input independence. Keep tests deterministic, and control external dependencies when time, randomness, or concurrent scheduling would obscure the behavior under examination.

Go example
package main
import "fmt"
func max(xs []int)(int,bool){ if len(xs)==0{return 0,false}; best:=xs[0]; for _,x:=range xs[1:] {if x>best {best=x}}; return best,true }
func main(){ fmt.Println(max([]int{-5,-2,-7})); fmt.Println(max(nil)) }
Result
-2 true
0 false

Initializing from the first element handles all-negative input; the boolean distinguishes empty input from a real maximum of zero.

Try it yourself

Write cases for one element, all negative values, duplicate maxima, zero, and empty input.

Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.

CHECK YOUR UNDERSTANDING

Chapter checkpoint

Which case exposes a maximum implementation that always initializes best to zero?