捕获常见错误

传统的测试观点是将其视为检查代码是否按预期工作的过程。单元测试在这方面表现出色,并自动化了使用已知输入运行代码并检查预期输出的过程。由于我们是人类,我们在编写代码时都会不时犯错误,其中一些错误可能会产生重大影响。我们可能会犯一些常见的简单错误,而单元测试擅长捕捉所有这些错误。最常见的错误包括:

  • 差一错误(Off-by-one errors)

  • 条件逻辑颠倒(Inverted conditional logic)

  • 缺少条件(Missing conditions)

  • 未初始化的数据(Uninitialized data)

  • 错误的算法(The wrong algorithm)

  • 损坏的相等性检查(Broken equality checks)

例如,回到我们之前的小写用户名测试,假设我们决定不使用内置的 String.toLowerCase() 方法来实现,而是尝试编写自己的循环代码,如下所示:

public class Username {
    private final String name;

    public Username(String username) {
        name = username;
    }

    public String asLowerCase() {
        var result = new StringBuilder();

        for (int i = 1; i < name.length(); i++) {
            char current = name.charAt(i);
            if (current > 'A' && current < 'Z') {
                result.append(current + 'a' - 'A');
            } else {
                result.append(current);
            }
        }

        return result.toString();
    }
}

我们会立即发现这段代码不正确。测试失败,如下图所示:

image 2025 01 11 23 46 14 384
Figure 1. Figure 5.3 – A common coding error

这段代码中的第一个错误是一个简单的差一错误——输出的第一个字母缺失了。这表明我们在初始化循环索引时出现了错误,但这段代码中还有其他错误。这个测试揭示了两个缺陷。进一步的测试还会揭示另外两个缺陷。你能仅通过视觉检查看出它们是什么吗?与使用自动化测试相比,像这样在头脑中分析代码需要多少时间和精力?