日常练习

以往的编程习惯总是先一口气写完功能,再补几个测试了事。这次,我决定严格按照 测试驱动开发(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 的逻辑,让测试变绿,然后进行重构(比如用正则表达式优化分隔符处理)。

posted @ 2026-02-28 10:21  老汤姆233  阅读(24)  评论(0)    收藏  举报