18、每次测一个功能

  在测试模式下,很容易去尝试对每个测试中的每件事都断言。这必须避免因为它使得维护更难。仅测试该测试方法的名字表明的功能。

  对于一般代码应该将测试代码尽可能少作为一个目标。

  19、使用显式断言

  在assertEquals(a, b)和assertTrue(a == b) (之类的)之间优先选择前者,因为它可以在测试失败的时候给出关于失败原因的更多有用的信息。 这对于上述提到的随机参数组合时输入值无法预先知道的情况尤为重要。

  20、提供负面测试

  负面测试是通过故意用错代码以验证稳健性和适当的错误处理。

  考虑下面这个如果传入负数会抛出异常的方法:

void setLength(double length) throws IllegalArgumentException;


  可以这样来测试该特殊情况的正确行为:

try
{
     setLength(-1.0);
     fail();    // If we get here, something went wrong
}
catch (IllegalArgumentException exception)
{
     // If we get here, all is fine
}


  21、设计代码是考虑测试

  编写和维护单体测试的代价很高,使公开API小化并降低代码的循环复杂度是降低成本并使得高覆盖率的测试代码更快编写和更易于维护的方式。

  一些建议:

  ● 通过构造时候确定状态来使得成员类不可变。这会减少对setter方法的需求。

  ● 限制过渡使用继承和虚的公开方法。

  ● 减少利用了友元类(C++)或包范围(Java)的公开API。

  ● 避免不必要的分支。

  ● 在分支内的代码尽可能少。

  ● 尽可能使用异常和断言来验证分别在公开和私有API中的参数。

  ● 限制使用帮助方法。从一个黑盒测试的角度每个方法都必须一样地测试。考虑如下这个小例子:

public void scale(double x0,double y0,double scaleFactor)
{
      // scaling logic
}
 
public void scale(double x0, double y0)
 
      scale(x0, y0, 1.0);
}


  省去后面的可以简化测试,但代价是客户端代码会有额外的工作。