首页 / 软件开发 / JAVA / 演化架构与紧急设计: 测试驱动设计,第2部分
演化架构与紧急设计: 测试驱动设计,第2部分2011-05-18 IBM Neal Ford本文是分两部分的文章的第二部分,讨论如何使用 TDD 在编写代码之前编写 测试,并通过这个过程形成更好的设计。在 第 1 部分 中,我采用后测试开发方 法(在编写代码之后编写测试)编写了完全数查找程序的一个版本。然后,使用 TDD(在编写代码之前编写测试,这样就可以用测试驱动代码的设计)编写了另一 个版本。在第 1 部分的末尾,我发现我在用来保存完全数列表的数据结构类型方 面犯了一个根本性错误:我最初根据直觉选用了 ArrayList,但是后来发现 Set 更合适。我将以这个问题为起点,讨论如何改进测试的质量和检查最终代码的质 量。测试质量使用更好的 Set 抽象的测试见清单 1:清单 1. 使用更好的 Set 抽象的单元测试_@Test public void add_factors() {
Set<Integer> expected =
new HashSet<Integer>(Arrays.asList(1, 2, 3, 6));
Classifier4 c = new Classifier4(6);
c.addFactor(2);
c.addFactor(3);
assertThat(c.getFactors(), is(expected));
}这段代码测试我的问题领域中最关键的部分之一:获取数字的因子。我希望彻 底地测试这个步骤,因为它是问题中最复杂的部分,所以也是最容易出现错误的 。但是,它包含一个笨重的构造:new HashSet(Arrays.asList(1, 2, 3, 6));。 即使有了现代 IDE 支持,这行代码编写起来也很别扭:输入 new,输入 Has,执 行代码探察;输入 <Int,再次执行代码探察,真是太麻烦了。我要让它容易 些。潮湿的测试Andy Hunt 和 Dave Thomas 所著的 The Pragmatic Programmer提出了许多良 好的编程实践,其中之一是 DRY(Don"t Repeat Yourself,不要重复自己)原则 。这条原则主张从代码中消除所有重复,因为重复常常会导致错误。但是,DRY 不适用于单元测试。单元测试常常需要测试有细微差异的代码行为,因此涉及到 相似和重复的情况。例如,为了在不同的测试中测试各种情况,常常需要复制粘 贴代码,以得出 清单 1 中预期的结果 (new HashSet(Arrays.asList(1, 2, 3, 6)))。对于 TDD,我的经验规则是测试应该是潮湿的,但是不要湿透。也就是说,测 试中可以有一些重复(而且这是不可避免的),但是不应该创建笨拙的重复结构 。因此,我要重构测试,提供一个 private 辅助方法,用它处理这个常用的创建 语句,见清单 2:清单 2. 保持测试适当潮湿的辅助方法private Set<Integer> expectationSetWith(Integer... numbers) {
return new HashSet<Integer>(Arrays.asList(numbers));
}