Test-Driven Development (TDD) Cheat Sheet
Core Principles
Test First**:
Always write a failing test before writing the production code.
Incremental Development
Take small steps. Write the simplest code to pass the current test, then refactor.
Red-Green-Refactor
Red: Write a test that fails and defines the desired behavior.
Green: Write the simplest code to pass the test.
Refactor: Improve code design while keeping tests passing.
Types of Tests
Unit Tests
Focus: Smallest testable unit of code (e.g., functions, methods, classes).
Goal: Verify the correctness of isolated components.
Integration Tests
Focus: Interaction between components or modules.
Goal: Ensure correct communication and data flow.
End-to-End (E2E) Tests
Focus: Simulate real user interactions with the entire application.
Goal: Ensure the application works from the user’s perspective.
Benefits of TDD
Enhanced code quality.
Fewer bugs.
Increased confidence in code.
Living documentation.
Faster feedback loops.
Test Pyramid
Base: Unit tests (fast, numerous, isolated).
Middle: Integration tests (fewer, slower).
Top: E2E tests (fewest, slowest).
Test Doubles
Dummy: Placeholder object that fulfills an interface with no implementation.
Fake: A working object, but not suitable for production (e.g., in-memory database).
Stub: Provides predefined responses to method calls.
Mock: A stub with expectations about how it should be called.
Spy: Wraps around a real object and records interactions for later verification.
Mockist vs. Classicist TDD
London School (Mockist): Heavy use of mocks to isolate units for faster feedback.
Detroit School (Classicist): Uses real objects and stubs, preferring mocks only when necessary.
Best Practices
Keep Tests Small & Focused: Each test should target a specific behavior (e.g., testCalculate, testSave).
Use Descriptive Test Names: Clearly state the purpose (e.g., testCalculateSumWithPositiveNumbers).
Isolate Dependencies: Use test doubles for external systems to create more reliable tests.
Maintain Test Coverage: Aim for high coverage but focus on critical paths and edge cases.
Don’t Test Implementation Details: Focus on behavior, not the underlying implementation.
Refactor Ruthlessly: Clean code is easier to test and maintain.