← Back to Go Course | Chapter 14: Standard Library & HTTP | Lesson 8 of 10

Writing Tests with the testing Package

Go's testing package lets you write little checkup scripts that automatically verify your code still works correctly every time you change something.
Syntax
go
// 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.

Note: Since Judge0 runs a single main.go, this example simulates test logic inside main() to show the assertion pattern -- real tests live in a _test.go file run via 'go test'.

Example: Writing a Basic Test

markup
// 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)
	}
}

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

markup
// 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)
	}
}

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

markup
// 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)")
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Naming a test function without the exact Test prefix (and capitalized), which 'go test' won't discover and run.
  2. Forgetting a test function must take exactly one parameter, *testing.T, or it won't be recognized as a valid test.
  3. Using t.Fatal inside a goroutine spawned by a test, which is unsafe -- t methods must be called from the test's own goroutine.
Chapter Summary
  • 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.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.