TDD测试驱动开发

红-绿-重构循环

// 第一步(红):编写失败的测试 // 测试尚未存在的功能 test('FizzBuzz 对 3 的倍数返回 "Fizz"', () => { expect(fizzBuzz(3)).toBe('Fizz'); // ❌ fizzBuzz 未定义 expect(fizzBuzz(6)).toBe('Fizz'); }); // 第二步(绿):编写最少代码使测试通过 function fizzBuzz(n) { if (n % 3 === 0) return 'Fizz'; // ✅ 只写必要的代码 return String(n); } // 第三步(重构):在不破坏测试的前提下改善代码 // 继续添加测试,然后完善实现: test('FizzBuzz 对 5 的倍数返回 "Buzz"', () => { expect(fizzBuzz(5)).toBe('Buzz'); }); test('FizzBuzz 对 15 的倍数返回 "FizzBuzz"', () => { expect(fizzBuzz(15)).toBe('FizzBuzz'); }); // 最终实现: function fizzBuzz(n) { if (n % 15 === 0) return 'FizzBuzz'; if (n % 3 === 0) return 'Fizz'; if (n % 5 === 0) return 'Buzz'; return String(n); }

TDD 方法对比

方法方向从何开始适合场景
由内而外(Detroit/Chicago)单元优先,后集成领域对象、纯逻辑熟悉的领域、算法实现
由外而内(London/Mockist)验收测试优先,Mock 协作者高层验收测试API 驱动设计、内部细节待定
BDD(行为驱动)用户场景优先Gherkin feature 文件跨团队沟通、验收标准

BDD 与 Gherkin

# Feature 文件(Gherkin 语法) 功能: 用户登录 作为一个注册用户 我希望能登录账户 以便访问我的仪表板 场景: 登录成功 假如 我在登录页面 当 我输入邮箱 "[email protected]" 和密码 "correct123" 并且 我点击"登录"按钮 那么 我应该被重定向到仪表板 并且 我应该看到"欢迎回来" 场景: 密码错误登录失败 假如 我在登录页面 当 我输入邮箱 "[email protected]" 和密码 "wrong" 并且 我点击"登录"按钮 那么 我应该看到"邮箱或密码不正确" 并且 我仍然停留在登录页面 # 步骤定义(JavaScript — Cucumber.js) Given('我在登录页面', async () => { await page.goto('/login'); }); When('我输入邮箱 {string} 和密码 {string}', async (email, password) => { await page.fill('#email', email); await page.fill('#password', password); });