1. Write tests alongside code
Don't wait until the end. Write tests as you write code.
2. Test behavior, not implementation
Test what the code does, not how it does it. This makes refactoring easier.
3. Use table-driven tests
For multiple test cases, use table-driven tests.
4. Test edge cases
Test boundary conditions, empty inputs, nil values, and error conditions.
5. Keep tests simple
Each test should verify one thing. Complex tests are hard to debug.
6. Use meaningful test names
Test names should describe what they're testing:
func TestAdd_PositiveNumbers(t *testing.T) { }
func TestAdd_NegativeNumbers(t *testing.T) { }
func TestAdd_Zero(t *testing.T) { }
7. Mock external dependencies
Use interfaces to make dependencies mockable, as discussed in section 8.6. This allows you to test your code in isolation without depending on external systems.
Go's testing tools are powerful and sufficient for most needs. Write tests alongside your code, use table-driven tests for multiple cases, and measure coverage to identify gaps. Good tests are an investment that pays off in reduced bugs and increased confidence in refactoring.