Unit Testing Fundamentals

In Go, testing is a first-class citizen. You don't need external libraries or assertion frameworks to write robust tests. The standard library testing package, combined with the go test command, provides everything needed to build production-grade test suites.


1. Writing Your First Test

All tests in Go follow a strict set of rules:

func TestAdd(t *testing.T) {
    result := Add(2, 3)
    expected := 5
    
    if result != expected {
        t.Errorf("Expected %d, but got %d", expected, result)
    }
}

2. Table-Driven Tests (The Go Way)

Table-driven testing is the idiomatic way to write multiple test cases for a single function without duplicating logic.

func TestAbs(t *testing.T) {
    cases := []struct {
        name     string
        input    int
        expected int
    }{
        {"positive", 10, 10},
        {"negative", -5, 5},
        {"zero", 0, 0},
    }

    for _, tc := range cases {
        t.Run(tc.name, func(t *testing.T) {
            got := Abs(tc.input)
            if got != tc.expected {
                t.Errorf("Abs(%d) = %d; want %d", tc.input, got, tc.expected)
            }
        })
    }
}

3. The go test Command


4. Initialization and Cleanup


Interview Pro-Tips: Why no Assert() function?

If an interviewer asks why Go doesn't have assert.Equal(expected, result):


Technical Summary

  1. testing.T: The object used to report failures and control test state.
  2. Errorf: Standard way to report a non-fatal failure.
  3. Fatalf: Stops the current test immediately if a critical invariant is violated.
  4. Structural: Tests are kept in the same package as the code they test.