不知代码实现逻辑时,如何践行测试驱动开发(TDD)?
问题场景
我有一年TDD实践经验,一直坚持测试行为而非实现。现在要开发React的「图片标记器」功能:用户点击图片,若点击坐标匹配特定人物/物体的坐标,返回true。已知可能用到getBoundingClientRect但不熟悉用法,陷入循环——TDD要求先写失败测试,但完全不知道怎么写测试和验证目标,不敢无测试实验代码,导致停滞。
对四个方案的反馈
方案1:创建独立的「playground」文件进行实验
这是非常合理且专业的做法。TDD的核心是驱动生产代码的开发,但实验性代码不属于生产代码范畴。你可以在项目外或项目内单独建playground/目录,专门测试getBoundingClientRect的用法、坐标计算逻辑,甚至快速搭一个极简React组件模拟点击场景。这种实验不违反TDD原则,只是帮你理清技术细节,为后续编写生产代码的测试打基础。
- 优势:完全隔离生产代码,不会污染主分支;快速验证技术可行性,帮你明确测试的验证逻辑。
方案2:创建实验分支编码后,回主分支按TDD重写
这个方案可行,但效率略低。创建实验分支探索功能实现没问题,但删除分支后在主分支重写属于重复劳动。可以调整为:在实验分支完成技术验证后,直接基于已有的理解在该分支补写测试,确保测试覆盖行为逻辑后再合并到主分支——只要最终合并的代码符合「测试定义行为,代码满足测试」的TDD核心,就不算违背原则,不必纠结于绝对的提交顺序。
- 注意:绝对不能把无测试的实验代码直接合并到主分支,必须补全测试后再合并。
方案3:放弃TDD先写代码再补测试
这是最不推荐的做法。一旦打破「测试先于代码」的习惯,很容易陷入「代码写完懒得补测试」的陷阱,违背你坚持TDD的初衷。而且先写代码再补测试,容易变成测试实现而非行为——你会不自觉地跟着已写的代码逻辑写测试,而非从用户行为出发定义预期。
方案4:先写空测试使其编译失败,编写代码后再补充测试内容
这个方案可作为过渡手段,但不能滥用。空测试能帮你先搭建测试框架的结构,比如:
test('点击图片中人物区域返回true', () => { // TODO: 补充测试逻辑 });
但关键是,你不能先写生产代码再补测试内容,而是要在补测试时先明确用户行为的预期(比如「点击坐标(100,200)属于人物区域时返回true」),再基于这个预期写生产代码。如果只是为了编译通过写空测试,之后直接写代码再补测试,本质还是方案3的变种,违背TDD原则。
整体建议
- 优先用方案1做技术验证:先在playground里搞清楚
getBoundingClientRect返回的坐标结构、如何将点击事件的clientX/clientY与目标区域坐标做对比。比如写一个极简脚本:
const img = document.createElement('img'); img.src = 'test.jpg'; img.style.width = '500px'; document.body.appendChild(img); img.onload = () => { const rect = img.getBoundingClientRect(); console.log(rect); // 查看坐标信息 // 模拟点击坐标 const clickX = rect.left + 100; const clickY = rect.top + 200; // 定义目标区域范围 const isInTarget = clickX > rect.left + 50 && clickX < rect.left + 150 && clickY > rect.top + 150 && clickY < rect.top + 250; console.log(isInTarget); };
搞懂这些细节后,你就能明确测试的预期:「当点击事件的坐标落在目标区域范围内时,组件返回true」。
- 从最小单元开始写测试:不要一开始就想写完整的组件测试,先拆分纯逻辑单元。比如先测试「给定目标区域坐标和点击坐标,判断是否匹配的函数返回正确结果」——这个函数不依赖React,纯逻辑,很容易写测试:
test('点击坐标在目标区域内返回true', () => { const targetArea = { left: 50, top: 150, right: 150, bottom: 250 }; const clickCoords = { x: 100, y: 200 }; expect(isClickInTarget(clickCoords, targetArea)).toBe(true); }); test('点击坐标在目标区域外返回false', () => { const targetArea = { left: 50, top: 150, right: 150, bottom: 250 }; const clickCoords = { x: 200, y: 300 }; expect(isClickInTarget(clickCoords, targetArea)).toBe(false); });
用TDD完成这个纯逻辑函数后,再集成到React组件中,测试组件的点击行为(比如模拟点击图片的某个位置,验证组件是否返回true)。
- 不要纠结绝对的「测试先于代码」:TDD的核心是用测试定义行为,再实现代码满足测试,而非机械地严格执行「先写测试再写代码」的步骤。如果某个技术细节完全不了解,先做实验性探索是合理的,这不属于生产代码的开发流程,不会违背TDD的初衷。
内容的提问来源于stack exchange,提问作者ElMoscaviador

