创建易读性测试

  如果你以前写过单元测试,你是否在单元测试上写了一个好的声明行?可许不是这样的,大多数开发者并不厌烦去写一个好的声明因为他们更加关心去写测试。

 假设你是团队中的一个新的开发者,你试图读一个单元测试。连接这个:

    _
Public Sub TestCalcParseNegative()
Dim c As New Calc
Assert.AreEqual(1000, c.Parse("-1, -1000")
End Sub


 作为一个简单的练习,如果你理解了上例中Calc分列方法的用法,你很可能可以进行很好的推测,但是他可以简单的作为人员数量的用例使得输出结果为1000:

 在组中返回大的负数作为一个正数。

  如果数字是负数且返回值为剩下几个数的总和作为一个正数,那么忽略第一个数字。

  返回相互作乘积运算而得的数字。

  现在请参考下面在单元测试之中的小改动:

    _
Public Sub Parse_NegativeFirstNum_ReturnsSumOfTheRestAsPositive()
Dim c As New Calc
Dim parsedSumResult As Integer = c.Parse("-1", "-1000")
Const SUM_WITH_IGNORED_FIRST_NUM As Integer = 1000
Assert.AreEqual(SUM_WITH_IGNORED_FIRST_NUM, parsedSumResult)
End Sub


 这个是不是比较容易理解呢?当声明消息消失之后,表达意图合适的地方是测试的名字。 如果你广泛的使用了它,你将会发现你不再需要读测试代码能明白代码测试的目的所在。事实上,你经常根本不需要写任何注释,因为代码,特别是那些带着实例的,他们自己是证明自己的。

 名字包含了三部分内容: 测试下方法的名字(解析),测试下的状态或者规则(带着第一个负数传递一个字符串),以及预期的输出或者运行情况(剩余数字的总和以一个正数的形式返回)。需要注意的是我从名称中将Test以及Calc这两个词删除。我已经知道这是一个属性的测试因此在此没有重复此信息的必要。我也知道这是一个在Calc类中的测试因为测试类经常是写给一个特殊类的(这个类也许已经被命名为CalcTests)。

 名字也许会很长,但是又有谁在乎呢?它读起来更像是一个标准英语的句子而且它使得一个新来的开发者更容易明白测试的内容。更是这样,当这个测试发生故障时,我们甚至不需要调试代码可以知道问题究竟出在哪里。

 需要注意的是,我已经在前面分别实际演示了通过在不同行中创建一个结果变量的方法从声明操作中进行分解操作。这样做至少有两个理由。第一个理由是,你可以为一个变量分配一个可读性强的名字,它可以包含结果,这样可以使你的声明行非常易于理解以及易于读。第二点是,测试下与对象相反的invocation 可能非常的长,它可能会使你的声明行延伸出屏幕的边缘之外,这样导致测试者向右滚屏。我个人而言,我认为这个是非常恼人的。

 我在我的测试中使用了很多常量以确保我的声明读起来像一本书。在先前的例子之中,你可以读到声明中说:“确保分解总数是与忽略第一个数后所得总和是相等的。” 为你的变量取一个很好的名字能够在某些程度上弥补对于测试的命名不足。

 当然,有时一个声明 消息是在一个单元测试中传递intent的好的方法。 一个好的声明消息始终能够解释什么因该会发生或者什么发生了而且为什么会出错。举个例子来说,“分列应该忽略掉第一个数字如果这个数字是个负数的话”,“分列不能够忽略掉第一个负数”,还有“X调用对象Y标记错误”这些都是有用的声明消息,它们很清晰的描述了结果的情况。


  在你的设置方法中避免部分相关的代码

  一个 方法是样例成员变量在测试中使用的一个好地方。你所有的测试,只有在一部分的测试中避免变量。他们可以为测试设置本地变量。如果你创建了部分相关的实例作为类的成员,用来在测试中简单的避免创建的副本,你应该使用在文章前面解释的工厂方法,使用部分相关变量使得你的代码和设置方法缺少易读性。一旦变量在一个或者每个测试中使用,那么他应该是 方法的一个成员和变量。

 Figure 5 展现了一个拥有两个成员变量的类的测试。但是他们中的一个(cxNum)只被部分使用。Figure 6 展现了如何在测试中替换代码从而使它更加易读的方法。


  总结

  像你所看到的,写单元测试并不是一个微不足道的任务,如果步骤正确,单元测试可以为开发者的生产力和代码的质量带来令人惊讶的提高,他可以帮助你去创建的应用程序含有更少的错误,同时也可以便于其他的开发者去洞察你的代码,但是他也需要在之前承担一个义务,确认遵循一些简单的规则。当方法并不是很好时,单元测试则可能达到一个相反的结果,从而浪费您的时间,并且使测试过程更加复杂。