# Test-Driven Development — JUnit 5 & Mockito

Source: https://www.skillbyai.com/en/java-testing/d-tdd

> Practise the red-green-refactor cycle and know when TDD helps.

## Tests first, in small steps

**Test-driven development (TDD)**, popularised by Kent Beck, writes the test **before** the code in a short cycle. **Red**: write a small failing test for the next bit of behaviour. **Green**: write the simplest code that makes it pass. **Refactor**: clean up the code and tests while keeping everything green. Repeat in minutes-long steps. Benefits: every line of production code is covered by a test that was seen to fail (so the test really checks something); designs come out **testable** and focused because you write the API from the caller's point of view first; and you get a fast feedback loop that reduces debugging. TDD works especially well for **business rules**, algorithms and bug fixes (write a test that reproduces the bug first). It is less natural for exploratory UI work or unknown APIs, where a quick spike followed by tests is common. TDD is a skill: start with katas (FizzBuzz, string calculator, bowling game) and small features before applying it to complex code.

## One red-green-refactor cycle

Test first, minimal implementation, then tidy up.

```java
// RED: a failing test for the next behaviour
@Test
void couponFlat50AppliesOnlyAboveMinimum() {
    assertEquals(5_000, Coupons.discountPaise("FLAT50", 20_000));
    assertEquals(0,     Coupons.discountPaise("FLAT50", 19_999));
}

// GREEN: simplest code that passes
final class Coupons {
    static long discountPaise(String code, long totalPaise) {
        if (code.equals("FLAT50") && totalPaise >= 20_000) return 5_000;
        return 0;
    }
}

// REFACTOR: once FESTIVE10 arrives too, extract a rule table, keeping all tests green
final class CouponsRefactored {
    private static final Map<String, CouponRule> RULES = Map.of(
        "FLAT50",    total -> total >= 20_000 ? 5_000 : 0,
        "FESTIVE10", total -> total / 10);
    static long discountPaise(String code, long totalPaise) {
        return RULES.getOrDefault(code, total -> 0).discountFor(totalPaise);
    }
    interface CouponRule { long discountFor(long totalPaise); }
}
```

## Fix bugs test-first

When a bug is reported, write a test that reproduces it and watch it fail, then fix the code. The test proves the fix and prevents the bug from silently returning.

**Quiz:** What are the three steps of the TDD cycle?

- [x] Red, green, refactor
- [ ] Plan, code, deploy
- [ ] Mock, stub, verify
- [ ] Compile, link, run

*Answer:* Red, green, refactor. Write a failing test (red), make it pass (green), then improve the code (refactor).
