什么是单元测试

首先需要介绍一下什么是单元测试。很多人像我一样,本科并不是计算机专业出身的,如果在职的公司不要求做单元测试的话,可能对这个词并没有一个确切的概念。而即使是计算机专业出身,如果毕业以后写的不多的话,可能对这个词的含义也不是很清楚。从名字上看,单元测试是为了测试某一个代码单元而写的测试代码。

但是什么叫“一个代码单元”呢?是一个模块、还是一个类、还是一个方法(函数)呢?不同的人、不同的语言,都有不同的理解。一般的定义,尤其是是在 OOP 领域,是一个类的一个方法。在此,我们也这样理解:单元测试,是为了测试某一个类的某一个方法能否正常工作,而写的测试代码。

我们举一个例子说明一下,假如你有一个类,定义如下:

public class Calculator {
  public int add(int one, int another) {        
    //为了简单起见,暂不考虑溢出等情况。
    return one + another;
    }
}

那么为了测试这个Calculator类的add()方法,我们可以写如下的单元测试代码:

public class CalculatorTest {
  public void testAdd() throws Exception {
    Calculator calculator = new Calculator();        
    int sum = calculator.add(1, 2);
    Assert.assertEquals(3, sum);
  }
}

这里的CalculatorTestCalculator对应的测试类。而这里的testAdd()就是add()这个方法对应的测试方法。所以,写单元测试,就是给你的每个类的每个 public 方法写对于的测试方法。非 public 方法我们一般是不测试的,虽然可以通过反射等手段去做,但是一般看来,非public方法是这个类的实现细节,我们并不关心,我们只关心某一个 public 方法的输入、输出。

一般来说,一个方法对应的测试方法主要分为 3 部分,以上面的测试方法为例:

  1. setup。一般是 new 出你要测试的那个类,以及其他一些前提条件的设置:Calculator calculator = new Calculator();
  2. 执行操作。一般是调用你要测试的那个方法,获得运行结果:int sum = calculator.add(1, 2);
  3. 验证结果。验证得到的结果跟预期中是一样的:Assert.assertEquals(3, sum);

一般来说,我们写单元测试,会用到一些单元测试框架。常见的 Java 单元测试框架有 JUnit、TestNG 等等。在这个系列的文章中,我采用 JUnit 4,这也是用的最多的一个测试框架。上面的第三部,Assert.assertEquals(3, sum); 用的就是JUnit里面的验证结果的方法,最常见的就是调用Assert类的一些assert方法。除了上面用到的assertEquals,还有assertTrue, assertNotNull等等。