Skip to content

Chapter 11: Testing

1 Table-Driven Tests

In other languages, you might write 10 separate test functions for 10 cases. In Go, we use a Table. It's cleaner.

go
func TestAdd(t *testing.T) {
    // The Table
    cases := []struct {
        A, B, Expected int
    }{
        {1, 1, 2},
        {5, 0, 5},
        {-1, 1, 0},
    }

    // The Loop
    for _, tc := range cases {
        result := Add(tc.A, tc.B)
        if result != tc.Expected {
            t.Errorf("Add(%d, %d) = %d; want %d", tc.A, tc.B, result, tc.Expected)
        }
    }
}

Anatomy of t *testing.T

  • t: The Controller.
  • t.Errorf: "Mark this test as Failed, log the message, but Continue running other tests."
  • t.Fatal: "Stop now. This is critical."

2 Mocks (The Stunt Double)

Why do we mock? If your test actually connects to GitHub, and your internet is down, your test fails. Code logic didn't break; the internet did. Tests must confirm LOGIC, not INFRASTRUCTURE.

We create a fake struct that "looks like" the real dependency (satisfies the Interface) but just returns dummy data.

🎓 Knowledge Check: Why do we use "Table-Driven Tests"?

Answer: To avoid code duplication. Instead of writing 10 separate test functions for 10 scenarios, we write one logic loop and feed it a slice (Table) of inputs and expected outputs.

3 The Visual Signal (The Crash Test Dummy)

Concept: Unit Testing. Signal: A Crash Test Dummy. We put a dummy in the car and smash it into a wall (Test Case) to see if the airbag works, so we don't kill a real person (User) later.

Released under the MIT License.