日常练习
以往的编程习惯总是先一口气写完功能,再补几个测试了事。这次,我决定严格按照 测试驱动开发(TDD) 的流程来完成一个小功能,看看这种“先写测试,再写代码”的传说到底有什么魔力。
一、 我选择的任务:实现一个简单的字符串计算器
需求是:编写一个函数 add(numbers),它可以接受一个字符串,返回所有数字的和。字符串中的数字用逗号分隔,例如 “1,2,3” 返回 6。这是一个经典且能逐步增加复杂度的入门题。
二、 严格遵守TDD的三步循环:红 -> 绿 -> 重构
第一步:红(编写一个会失败的测试)
我先不写任何实现代码,而是直接写测试。我用了熟悉的JUnit。
@Test
public void testAddWithTwoNumbers() {
StringCalculator calculator = new StringCalculator();
int result = calculator.add("1,2");
assertEquals(3, result); // 此时编译都通不过,因为没有StringCalculator类
}
运行测试,果然失败了(红色)。但这正是TDD的第一步:明确需求,定义接口。
第二步:绿(用最简单的方式让测试通过)
为了让测试变绿,我写了最少的代码。
public class StringCalculator {
public int add(String numbers) {
return 3; // 硬编码,只为了让第一个测试通过!
}
}
再次运行测试,通过了(绿色)。虽然代码很蠢,但TDD的核心是小步快跑,确保每一次改动都有测试保护。
第三步:重构(改进代码,保持测试为绿)
现在有了测试的保护,我可以放心重构了。显然,硬编码不行。我实现了一个简单但正确的逻辑:
public int add(String numbers) {
if (numbers.isEmpty()) {
return 0;
}
String[] nums = numbers.split(",");
int sum = 0;
for (String num : nums) {
sum += Integer.parseInt(num);
}
return sum;
}
运行测试,依然是绿色。重构完成。
三、 循环继续:增加新需求,重复红-绿-重构
接下来,我需要处理“空字符串返回0”的需求。我先写测试:
@Test
public void testAddWithEmptyString() {
StringCalculator calculator = new StringCalculator();
int result = calculator.add("");
assertEquals(0, result);
}
运行,测试通过(绿)!因为我的代码已经处理了空字符串。这是一个好迹象,说明之前的重构考虑到了这个边界情况。
然后,我增加“允许处理未知数量的数字”的测试,测试也直接通过(绿)。直到我增加“允许换行符作为分隔符”这个新需求时,测试才再次变红。这时,我再修改 split 的逻辑,让测试变绿,然后进行重构(比如用正则表达式优化分隔符处理)。

浙公网安备 33010602011771号