WEB开发网
开发学院软件开发Java 演化架构与紧急设计: 测试驱动设计,第 1 部分 阅读

演化架构与紧急设计: 测试驱动设计,第 1 部分

 2009-11-05 00:00:00 来源:WEB开发网   
核心提示: 把程序划分为多个可执行一项可识别任务的方法,把方法中的所有操作保持在同一个抽象级别这将自然而然地得到拥有许多小方法的程序,演化架构与紧急设计: 测试驱动设计,第 1 部分(9),每个小方法都只有几行代码,组合方法是 TDD 提倡的有益设计特性之一,我将比较一下两个代码库,我还将解答其他某些棘手的

把程序划分为多个可执行一项可识别任务的方法。

把方法中的所有操作保持在同一个抽象级别

这将自然而然地得到拥有许多小方法的程序,每个小方法都只有几行代码。

组合方法是 TDD 提倡的有益设计特性之一,而我已经在 清单 11 的 getFactors() 方法中明显违反了这种模式。我可以通过执行以下步骤来修正:

将 factors 提升为内部状态。

将 factors 的初始化代码移到构造函数中。

去掉对 int[] 代码的转换,等到它变得有益时再处理它。

添加 addFactors() 的另一项测试。

第四步非常微妙但是很重要。编写出这个有缺陷的代码版本揭示出分解的第一步并不完整。隐藏在这个长方法中间的 addFactors() 代码行是可测试的行为。它是如此地微不足道,以至于在第一次查看问题时我都没有注意到它,但是现在我看到了。这是经常出现的情况。一个测试可以指引您进一步将问题分解为越来越小的块,每个块都是可以测试的。

我将暂停处理 getFactors() 的比较大的问题,而处理我新遇到的小问题。因此,我的下一个测试是 addFactors(),如清单 12 中所示:


清单 12. 测试 addFactors()
@Test public void add_factors() { 
  Classifier3 c = new Classifier3(6); 
  c.addFactor(2); 
  c.addFactor(3); 
  assertThat(c.getFactors(), is(Arrays.asList(1, 2, 3, 6))); 
} 

清单 13 所示的测试中的代码本身十分简单:


清单 13. 添加因子的简单代码
public void addFactor(int factor) { 
  _factors.add(factor); 
} 

我运行我的单元测试,充满信心地认为我会看到表示测试成功的绿条,但是却失败了!这样一个简单的测试怎么会失败?根本原因显示在图 2 中:


图 2. 测试失败的根本原因
演化架构与紧急设计: 测试驱动设计,第 1 部分

我期望看到的列表有 1, 2, 3, 6 几个值,而实际返回的是 1, 6, 2, 3。那是因为我将代码改为在构造函数中添加 1 和数字本身。这个问题的一种解决方案是,始终在假定应先添加 1 和该数字的情况下编写期望的代码。但是这是正确的 解决方案吗?不是。问题更为基础。因子是不是一个数字列表?不是,它们是一个数字集合。我的第一个(错误)假定导致我使用一列整数作为因子,但是这是个糟糕的抽象。通过将我的代码重构为使用集合而非列表,我不但解决了这个问题,而且优化了整个解决方案,因为我现在使用的是更精确的抽象。

如果在让代码影响您的判断力之前编写测试,这正是测试可以揭露的有缺陷的思维方式。现在,由于这项简单的测试,我编写的代码的整体设计更好了,因为我已经发现了更合适的抽象。

结束语

到目前为止,我以处理完全数为背景讨论了紧急设计。特别是,注意第一版的解决方案(后测试版本)对数据类型做出了同样有缺陷的假设。“后测试” 将测试代码的粗糙功能,而非各个部分。TDD 将测试构成粗糙功能的构建块,在测试过程中揭露更多信息。

在下一期文章中,我将继续讨论完全数问题,演示在执行测试时形成的各种设计的更多示例。在我完成 TDD 版本时,我将比较一下两个代码库。我还将解答其他某些棘手的 TDD 设计问题,例如是否测试及何时测试私有方法。

上一页  4 5 6 7 8 9 

Tags:演化 架构 紧急

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接