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.
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. Unit tests isolate logic with controlled dependencies. Integration tests also need to check actual infrastructure behavior, such as constraints, transactions, and cancellation. Fakes do not establish those guarantees.
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.
