演化架构与紧急设计: 测试驱动设计,第 2 部分
2009-11-05 00:00:00 来源:WEB开发网本文是分两部分的文章的第二部分,讨论如何使用 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)))。
更多精彩
赞助商链接