我们如何在TDD中组织单元测试?

时间:2020-03-06 14:55:27  来源:igfitidea点击:

我做TDD,在组织单元测试方面我一直很松懈。我倾向于从代表下一个故事或者功能块的文件开始,并编写所有单元测试以使该工作正常进行。

当然,如果要引入一个新类,通常会为该类制作一个单独的单元测试模块或者文件,但是我不会将测试本身组织成任何更高层次的结构。结果是我快速编写了代码,并且我相信我的实际程序结构合理,但是单元测试本身是"混乱的"。特别地,它们的结构倾向于概括发育过程的系统发育。有时候,我认为自己在测试中将懒惰视为交易中的懒惰。

这有多大问题?谁在这里不断重构和重组其单元测试以尝试改善其总体结构?有什么提示吗?测试的总体结构应该是什么样的。

(请注意,我并不是在这里问"每个功能有多少个断言"的问题:每个功能/方法应写多少个单元测试?我是在说大图。)

解决方案

我为应用程序中的每个类编写了一个单元测试类,并使测试类与被测类保持相同的包结构。

在每个测试类中,我实际上没有太多的组织结构。对于被测类中的每个公共方法,每个方法只有少数几种方法,因此,我在查找所需内容时从来没有遇到任何问题。

我尝试将单元测试视为一个项目。与任何项目一样,组织应遵循一些内部逻辑。但是,只要我们保持项目的井井有条和整洁,就不必特别定义或者正式定义我们满意的任何内容。

因此,对于单元测试,我通常或者遵循主要项目代码结构,或者(有时在情况需要时)关注功能区域。

就像我们想象的那样,将它们留在一个堆中,并且很难维护

将测试分为2组:

  • 功能测试
  • 单元测试

功能测试是针对每个用户的故事。单元测试是按班级进行的。前者检查我们是否确实支持该故事,后者检查并记录功能。

有一个用于功能测试的目录(程序包)。单元测试应该与它们行使的功能紧密结合(因此它们是分散的)。我们移动它们并在重构和重构代码时对其进行重构。

对于软件中的每个类,我都维护一个单元测试类。单元测试类与所测试的类遵循相同的包层次结构。

我将单元测试代码保存在一个单独的项目中。有些人还喜欢将测试代码保存在同一项目中的单独源代码目录下,称为" test"。我们可以按照自己感觉舒适的方式进行操作。

不太重要的部分是组织测试。

首先将测试放入与被测类相关的类中,因此com.jeffreyfredrick.Foo具有测试com.jeffreyfredrick.FooTest。但是,如果这些类的某些子集需要不同的设置,那么我将其移入他们自己的测试类。我将测试放入单独的源目录中,但将其保留在同一项目中。

更重要的部分是重构测试。

是的,我会尝试重新构建测试。目标是删除重复项,同时仍保持声明性且易于阅读。在测试类中和跨测试类都是如此。在测试类中,我可能具有用于创建测试假(模拟或者存根)的参数化方法。我的测试伪造品通常是测试类中的内部类,但是如果我发现有需要,我会把它们拉出来,以便在测试中重复使用。在合适的时候,我还将使用通用方法创建一个TestUtil类。

我认为重构测试对于大型项目的单元测试的长期成功很重要。我们是否听说过有人抱怨他们的测试过于脆弱或者无法更改?我们不想处于这样的位置,即更改类的行为意味着对测试进行数十甚至数百次更改。就像使用代码一样,我们可以通过重构并保持测试干净来实现这一点。

测试是代码。