TDD is a software development methodology where you write tests first and then the production code. In Jurassic Park, it is like first designing all the security systems and only then bringing in the dinosaurs.
TDD is based on three repeating steps:
1// STEP 1: We write the test BEFORE the production code
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// Result: RED - createFence does not exist!1// STEP 2: We write the simplest code that passes the test
2function createFence(zone, voltage) {
3 return {
4 zone,
5 voltage,
6 isActive: true
7 };
8}
9// Result: GREEN - test passes!1// STEP 3: We improve the code (tests still green!)
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// Result: GREEN - tests still pass after refactoring!Let's build a dinosaur feeding system step by step:
1// RED: Write the 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: Minimal implementation
9class DinoFeeder {
10 feed(species, food) {
11 return { success: true };
12 }
13}
14// Test passes - but the implementation is too simple!1// RED: Add test for incorrect food
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: Extend the implementation
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 for unknown species
2test('unknown species throws error', () => {
3 const feeder = new DinoFeeder();
4 expect(() => feeder.feed('Unknown', 'meat')).toThrow('Unknown species');
5});
6
7// GREEN: Add error handling
8class DinoFeeder {
9 // ... previous code ...
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 leads to:
2const tddBenefits = {
3 betterDesign: 'Code is designed for tests = better design',
4 lessDebugging: 'Bugs caught immediately',
5 documentation: 'Tests document code behavior',
6 confidence: 'Confidence during changes and refactoring',
7 coverage: '100% code coverage by definition'
8};