- Workshop documentation (WORKSHOP_PLAN, FACILITATOR_GUIDE, etc.) - FizzBuzz kata with demo script (git history to be recreated) - Password Validator kata with demo script and solution - Shopping Cart kata with demo script and solution - Setup guide and TDD reference card for participants
7.8 KiB
TDD Reference Card
Quick reference for Test-Driven Development practice
The RED-GREEN-REFACTOR Cycle
┌─────────────────────────────────────────────────┐
│ │
│ 1. RED Write a failing test │
│ ↓ (Proves the test can fail) │
│ │
│ 2. GREEN Write minimal code to pass │
│ ↓ (Make it work, don't make it perfect)│
│ │
│ 3. REFACTOR Clean up code │
│ ↓ (Remove duplication, improve names)│
│ │
│ 4. REPEAT Next failing test │
│ ↑ │
│ └───────────────────────────────────────────┘
The Discipline
RED - Write a Failing Test
- Write the test first, before any production code
- Run it and watch it fail (RED ❌)
- Make sure it fails for the right reason
- If it passes immediately, the test isn't testing anything new
GREEN - Make It Pass
- Write the simplest code that makes the test pass
- Don't worry about perfection yet
- Hardcoding is okay if it passes the test
- Run the test and see it pass (GREEN ✅)
- If you're tempted to write "just one more line"—STOP and run the test
REFACTOR - Clean Up
- Now that tests are passing, improve the code
- Remove duplication
- Clarify names
- Extract methods or classes
- Run tests after every change to ensure they stay green
- If tests go RED during refactoring, undo and try smaller steps
When to Refactor
Look for these code smells:
| Smell | Refactoring |
|---|---|
| Duplication | Extract method, introduce constant |
| Unclear names | Rename variable/method/class |
| Long method | Extract smaller methods |
| Nested conditionals | Extract methods, introduce polymorphism |
| Magic numbers | Replace with named constants |
| God class | Split responsibilities into multiple classes |
Rule of thumb: If you have to write a comment explaining what code does, the code needs better names.
Common Test Patterns
Arrange-Act-Assert (AAA)
test('calculates total price correctly', () {
// ARRANGE - Set up test data
final cart = ShoppingCart();
cart.addItem(CartItem(name: 'Apple', price: 1.50, quantity: 3));
// ACT - Perform the action being tested
final total = cart.subtotal();
// ASSERT - Verify the result
expect(total, equals(4.50));
});
setUp() for Common Setup
void main() {
late Calculator calculator;
setUp(() {
calculator = Calculator(); // Runs before EACH test
});
test('adds two numbers', () {
expect(calculator.add(2, 3), equals(5));
});
}
Test Naming
Use descriptive names that explain what is being tested:
✅ Good: test('rejects password shorter than 8 characters', ...)
❌ Bad: test('test1', ...) or test('validation works', ...)
Dart Test Assertions - Quick Reference
// Equality
expect(actual, equals(expected));
expect(result, isTrue);
expect(result, isFalse);
// Comparison
expect(value, greaterThan(10));
expect(value, lessThan(5));
expect(value, closeTo(0.30, 0.001)); // For floating point
// Type checks
expect(object, isA<String>());
expect(value, isNull);
expect(value, isNotNull);
// Collections
expect(list, isEmpty);
expect(list, isNotEmpty);
expect(list, contains('item'));
expect(list, containsAll(['a', 'b']));
expect(list, hasLength(3));
// Exceptions
expect(() => validatePassword(''), throwsArgumentError);
expect(() => divide(1, 0), throwsA(isA<DivisionByZeroException>()));
// Strings
expect(text, startsWith('Hello'));
expect(text, endsWith('world'));
expect(text, matches(RegExp(r'\d+')));
Quick Tips for TDD Success
1. Start Small
Begin with the simplest possible test:
- Empty input → sensible output
- Single item → correct behavior
- Then add complexity
2. One Test at a Time
- Uncomment or write one test
- Make it pass
- Then move to the next
- Don't skip ahead!
3. Baby Steps
Each cycle should take 2-5 minutes, not 20 minutes:
- If a test takes too long, it's testing too much
- Break it into smaller tests
4. Run Tests Frequently
After every code change:
- Immediately see if something broke
- Faster feedback = faster learning
5. Trust the Process
The design emerges from the tests:
- You don't need to design everything upfront
- Simple tests lead to general solutions
- Complex scenarios often work without explicit implementation
6. Refactor Fearlessly
With passing tests, you can:
- Rename aggressively
- Restructure boldly
- Optimize confidently
- If tests go RED, just undo
Common Mistakes to Avoid
| Mistake | Why It's Bad | Fix |
|---|---|---|
| Writing code before test | No way to know if test is valid | Always RED first |
| Writing multiple tests at once | Overwhelming, loses focus | One test at a time |
| Skipping REFACTOR | Technical debt accumulates | Clean up after each GREEN |
| Not running tests after refactor | Might break something unknowingly | Run tests constantly |
| Testing implementation details | Tests become brittle | Test behavior, not internals |
| Making tests pass by hardcoding | Doesn't prove general solution | Add another test to force generalization |
What to TDD vs. What to Skip
✅ Great for TDD:
- Business logic: Calculations, validations, algorithms
- Domain models: Value objects, entities with rules
- Utilities: String parsers, formatters, converters
- APIs: Request/response handling, error cases
⚠️ Less Useful for TDD:
- UI layouts: Visual appearance is hard to test
- Framework glue: Wiring dependencies, configuration
- Database queries: Better tested with integration tests
- Third-party integrations: Better mocked or integration tested
Rule: If behavior matters and can be verified programmatically, use TDD.
When You Get Stuck
"I don't know what test to write next"
Ask: "What's the simplest behavior this doesn't handle yet?"
- Start with zero/empty cases
- Then one item
- Then two items
- Then edge cases
"The test is too complex"
Break it down:
- Can you test just one part of the behavior?
- Can you introduce a helper method to simplify setup?
"I can't make it pass without writing a lot of code"
That's a sign:
- The test might be too big (break into smaller tests)
- OR you're missing an intermediate test
- OR you need to refactor existing code first
"Tests are passing but the design feels wrong"
Good news:
- You have tests as a safety net!
- Refactor now while tests are green
- Improve names, extract methods, restructure
Resources for More Practice
After This Workshop:
- tdd-katas repo: github.com/dhemasnurjaya/tdd-katas
- 5 complete katas with commit history
- Roman Numerals, Bowling Game, Gilded Rose, String Calculator, Mars Rover
Books:
- Test-Driven Development by Kent Beck
- Clean Code by Robert C. Martin
- Growing Object-Oriented Software, Guided by Tests by Freeman & Pryce
Online Katas:
- Kata-Log (kata-log.rocks)
- Coding Dojo (codingdojo.org)
- Exercism (exercism.org)
Remember
"Clean code that works." — Ron Jeffries
TDD is a skill. Like any skill:
- It feels awkward at first
- Practice makes it automatic
- The rhythm becomes second nature
Keep practicing. Keep the cycle tight. Let the tests guide you.