Test Writer
Decision Tree
code
Need to write a test → What kind?
├─ Testing a pure function → Unit test, no mocking needed
├─ Testing a class with dependencies → Unit test, mock dependencies
├─ Testing API endpoint → Integration test, real server + test DB
├─ Testing user workflow → E2E test (Playwright / platform integration test)
└─ Testing UI appearance → Snapshot test
What to Test
| Always Test | Skip |
|---|---|
| Business logic / core algorithms | Framework internals |
| Edge cases (empty, null, boundary) | Simple getters/setters |
| Error paths and error messages | Third-party library behavior |
| State transitions | Private methods (test via public API) |
| Integration points (API, DB) | UI layout pixel-perfection |
| Security-sensitive paths (auth, validation) | Generated code |
Naming Convention
code
test_[unit]_[scenario]_[expected result] # Examples: test_login_with_valid_credentials_returns_token test_login_with_expired_password_returns_403 test_cart_add_item_when_full_raises_limit_error
Assertion Best Practices
- •One logical assertion per test - Test one behavior, not one
assertstatement - •Assert on behavior, not implementation - Check return values, not internal state
- •Use specific assertions -
assertEqual(x, 5)notassertTrue(x == 5) - •Include failure messages -
assertEqual(result, 5, "discount should be 5% for VIP") - •Test exact error types -
assertRaises(ValueError)notassertRaises(Exception)
Mocking Strategy
| Mock | Don't Mock |
|---|---|
| External APIs / HTTP calls | The unit under test |
| Database (in unit tests) | Simple value objects |
| File system / network | Pure functions |
| Time / randomness | Internal collaborators (usually) |
| Third-party services | Everything (over-mocking = brittle tests) |
Anti-Patterns
| Anti-Pattern | Problem | Fix |
|---|---|---|
| Testing implementation details | Breaks on refactor | Test behavior/output |
| Flaky tests ignored | Erode trust in test suite | Fix or delete immediately |
| Copy-paste test setup | Hard to maintain | Use fixtures/factories |
| No assertion (test just "runs") | Proves nothing | Always assert expected outcome |
| Testing too much in one test | Unclear what failed | One behavior per test |
| Mocking everything | Tests prove nothing | Only mock boundaries |
Test Structure (Arrange-Act-Assert)
code
# Arrange - Set up inputs and expected outputs user = create_user(role="admin") # Act - Call the function under test result = permissions.can_delete(user, resource) # Assert - Verify the result assert result is True
Coverage Targets
- •New code: 80%+ line coverage
- •Critical paths (auth, payments, data): 95%+
- •Don't chase 100%: Diminishing returns past 85% overall