TDD to metodologia tworzenia oprogramowania, w której najpierw piszesz testy, a dopiero potem kod produkcyjny. W Parku Jurajskim to jak najpierw zaprojektowanie wszystkich systemów bezpieczeństwa, a dopiero potem sprowadzenie dinozaurów.
TDD opiera się na trzech powtarzających się krokach:
1// KROK 1: Piszemy test PRZED kodem produkcyjnym
2describe('FenceSystem', () => {
3 it('should create a fence with voltage', () => {
4 const fence = createFence('Zone A', 10000);
5
6 expect(fence.zone).toBe('Zone A');
7 expect(fence.voltage).toBe(10000);
8 expect(fence.isActive).toBe(true);
9 });
10});
11// Wynik: RED - createFence nie istnieje!1// KROK 2: Piszemy najprostszy kod, który przejdzie test
2function createFence(zone, voltage) {
3 return {
4 zone,
5 voltage,
6 isActive: true
7 };
8}
9// Wynik: GREEN - test przechodzi!1// KROK 3: Ulepszamy kod (testy nadal zielone!)
2class Fence {
3 constructor(zone, voltage) {
4 this.zone = zone;
5 this.voltage = voltage;
6 this.isActive = true;
7 }
8
9 getStatus() {
10 return this.isActive ? 'ACTIVE' : 'OFFLINE';
11 }
12}
13
14function createFence(zone, voltage) {
15 return new Fence(zone, voltage);
16}
17// Wynik: GREEN - testy nadal przechodzą po refaktorze!Zbudujmy system karmienia dinozaurów krok po kroku:
1// RED: Piszemy test
2test('carnivore eats meat', () => {
3 const feeder = new DinoFeeder();
4 const result = feeder.feed('T-Rex', 'meat');
5 expect(result.success).toBe(true);
6});
7
8// GREEN: Minimalna implementacja
9class DinoFeeder {
10 feed(species, food) {
11 return { success: true };
12 }
13}
14// Test przechodzi - ale implementacja jest zbyt prosta!1// RED: Dodajemy test dla niepoprawnego jedzenia
2test('carnivore rejects plants', () => {
3 const feeder = new DinoFeeder();
4 const result = feeder.feed('T-Rex', 'plants');
5 expect(result.success).toBe(false);
6 expect(result.reason).toBe('Wrong diet');
7});
8
9// GREEN: Rozszerzamy implementację
10class DinoFeeder {
11 constructor() {
12 this.diets = {
13 'T-Rex': 'carnivore',
14 'Triceratops': 'herbivore',
15 'Velociraptor': 'carnivore',
16 };
17 }
18
19 feed(species, food) {
20 const diet = this.diets[species];
21
22 if (diet === 'carnivore' && food !== 'meat') {
23 return { success: false, reason: 'Wrong diet' };
24 }
25 if (diet === 'herbivore' && food !== 'plants') {
26 return { success: false, reason: 'Wrong diet' };
27 }
28
29 return { success: true };
30 }
31}1// RED: Test dla nieznanego gatunku
2test('unknown species throws error', () => {
3 const feeder = new DinoFeeder();
4 expect(() => feeder.feed('Unknown', 'meat')).toThrow('Unknown species');
5});
6
7// GREEN: Dodajemy obsługę błędów
8class DinoFeeder {
9 // ... poprzedni kod ...
10
11 feed(species, food) {
12 const diet = this.diets[species];
13
14 if (!diet) {
15 throw new Error('Unknown species');
16 }
17
18 if (diet === 'carnivore' && food !== 'meat') {
19 return { success: false, reason: 'Wrong diet' };
20 }
21 if (diet === 'herbivore' && food !== 'plants') {
22 return { success: false, reason: 'Wrong diet' };
23 }
24
25 return { success: true };
26 }
27}1// TDD prowadzi do:
2const tddBenefits = {
3 betterDesign: 'Kod jest projektowany pod testy = lepszy design',
4 lessDebugging: 'Błędy wyłapywane natychmiast',
5 documentation: 'Testy dokumentują zachowanie kodu',
6 confidence: 'Pewność przy zmianach i refaktorze',
7 coverage: '100% pokrycia kodu testami z definicji'
8};