Writing Tests with the testing Package
In this page:
// file_test.go
func TestName(t *testing.T) {
got := function(input)
if got != want {
t.Errorf("got %v, want %v", got, want)
}
}
Writing a Basic Test
A test function is named TestXxx, takes a *testing.T, and calls t.Errorf (or t.Fatalf) when an expected result doesn't match the actual one. Here the same check is demonstrated directly in main so it can run and print output.
Example: Writing a Basic Test
// Every Go file belongs to a package; main builds an executable
package main
// Import the fmt package
import "fmt"
// Define the function add
func add(a, b int) int {
// Send a + b back to the caller
return a + b
}
// main is where the program starts running
func main() {
// Short declaration: create got and infer the type
got := add(2, 3)
// Short declaration: create want and infer the type
want := 5
// Check whether got != want
if got != want {
fmt.Printf("FAIL: add(2,3) = %d, want %d\n", got, want)
} else {
fmt.Println("PASS: add(2,3) =", got)
}
}
Login to try C/C++/Java/PHP code in the editor
Table-Driven Tests
A table-driven test defines a slice of input/expected-output cases and loops over them, running the same assertion logic for each -- the idiomatic Go way to cover many cases without duplicating test code.
Example: Table-Driven Tests
// Every Go file belongs to a package; main builds an executable
package main
// Import the fmt package
import "fmt"
// Define the function square
func square(n int) int {
// Send n * n back to the caller
return n * n
}
// main is where the program starts running
func main() {
// Short declaration: create cases and infer the type
cases := []struct {
input, want int
}{
{2, 4},
{3, 9},
{5, 25},
}
// Loop over cases; the blank identifier _ ignores the index
for _, c := range cases {
// Short declaration: create got and infer the type
got := square(c.input)
status := "PASS"
if got != c.want {
status = "FAIL"
}
fmt.Printf("%s: square(%d) = %d\n", status, c.input, got)
}
}
Login to try C/C++/Java/PHP code in the editor
Errorf vs Fatalf
t.Errorf marks the test as failed but lets it keep running (useful for reporting multiple issues in one test), while t.Fatalf marks it failed and immediately stops that test function, useful when continuing would panic.
Example: Errorf vs Fatalf
// Every Go file belongs to a package; main builds an executable
package main
// Import the fmt package
import "fmt"
// Define the function divide
func divide(a, b int) (int, bool) {
// Check whether b == 0
if b == 0 {
// Send 0, false back to the caller
return 0, false
}
// Send a / b, true back to the caller
return a / b, true
}
// main is where the program starts running
func main() {
// Check whether _, ok := divide(10, 0); !ok
if _, ok := divide(10, 0); !ok {
fmt.Println("caught invalid division, stopping this check (like t.Fatalf)")
}
fmt.Println("continuing with other checks (like t.Errorf would allow)")
}
Login to try C/C++/Java/PHP code in the editor
- Naming a test function without the exact Test prefix (and capitalized), which 'go test' won't discover and run.
- Forgetting a test function must take exactly one parameter, *testing.T, or it won't be recognized as a valid test.
- Using t.Fatal inside a goroutine spawned by a test, which is unsafe -- t methods must be called from the test's own goroutine.
- Test functions live in _test.go files and are named TestXxx, taking a *testing.T parameter.
- t.Errorf reports a failure but lets the test continue; t.Fatalf reports a failure and stops immediately.
- 'go test' automatically discovers and runs every TestXxx function in a package.
- Table-driven tests, iterating over a slice of input/expected pairs, are the idiomatic Go testing style.
Chapter Quiz — Complete all 10 topics to unlock
0/10 topics done
Complete these topics first: