首先需要明白什么是单元,一般来说,一个单元是指类中的一个方法,而且是公开的方法。因为我们认为非公开的方法是类的实现细节,不需要关心,我们只关心向这些公开方法传入参数后它能否正常工作,得到正确的结果。所以单元测试也就是对方法的测试。
再来说说为什么要进行单元测试, 如果不进行单元测试,我们需要将一个功能的整套逻辑编写完毕并运行后才能知道逻辑是否正确,如果不正确还要进行反复的修改运行的重复,非常耗时。通过单元测试,我们确保每一个方法的正确性,虽然这也不能确保这个工作流程不会出问题,但是可以大大降低出现bug的几率。
接下来再来看看Junit,这是一个在JAVA中最常见也是最基础的测试框架。一般来说,我们进行单元测试,在类中写一个main方法然后运行也可以实现,但是效率太低。借助这个框架和他便利的API我们可以快速实现一个或多个方法的测试。
使用方法:
1.新建测试类:在我的项目结构目录(AS2.3.1)下可以看到三个名称相同的包,其中一个标记为test,这就是包含测试类的包。在下面新建一个类文件。
2.编写测试方法:一般来说,测试方法包括三个部分,初始化对象、调用方法、比较执行结果。举例说明:
@Test
public void testAdd() throws Exception {
Calculator calculator = new Calculator();
int sum = calculator.add(1, 2);
Assert.assertEquals(3, sum);
}
如上,首先实例化了一个对象,然后调用这个对象的方法并获得返回值,最后比较这个返回值和期望值,相同的话则测试通过。这些比较方法由Assert提供,不过我在最新的框架版本中已经不需要写这个类名了,可以直接调用。实际上,JUNIT主要测试的就是有返回值的方法。
方法前的Test注解就表示这是个测试方法,框架就是根据这个注解来识别运行这个方法的。
3.全部的比较方法:
assertEquals(expected, actual)
验证expected的值跟actual是一样的,如果传入的是object,那么这里的对比用的是equals()
assertEquals(expected, actual, tolerance)
这里传入的expected和actual是float或double类型的,针对浮点数,如果两个数的差异在这个偏差值之内,则测试通过,否者测试失败。(浮点数偏差性)
assertTrue(boolean condition)
验证contidion的值是true
assertFalse(boolean condition)
验证contidion的值是false
assertNull(Object obj)
验证obj的值是null
assertNotNull(Object obj)
验证obj的值不是null
assertSame(expected, actual)
验证expected和actual指向同一个对象
assertNotSame(expected, actual)
验证expected和actual指向不同的对象
fail()
让测试方法失败
fail也是有用的,它可以让你知道这个测试方法确实被调用了。
4.测试优化:
如果我们要测试一个类中的多个方法的话,不难发现我们需要在多个方法里重复同一个实例化过程,为了消除这个过程,我们可以借助标签@Before:
Calculator mCalculator;
@Before
public void setup() {
mCalculator = new Calculator();
}
如上所示,首先在类中定义一个全局变量,然后在一个有BEFORE标签的方法中将他实例化。被这个标签修饰后,每个测试方法开始运行前都需要调用一次这个方法。与它对应的标签是@After
另外一组对应的标签是@BeforeClass,@AfterClass,这两个修饰的方法会分别在类所有方法测试前后执行。
忽略:如果我们想要执行一个测试类中全部方法而忽略几个方法的时候可以直接在方法前加标签@Ignore。
测试异常:如果我们想要测试一个方法能否正常抛出异常可以设置标签的expected:
@Test(expected = IllegalArgumentException.class)
public void test() {
mCalculator.divide(4, 0);
}
如上,只有方法抛出指定的这个异常类才能通过测试。
5.执行测试:
在最新版的AS上,测试方法和测试类前面都有运行按钮,当然也可以通过右键快捷键进行执行。这个执行过程是比较快的,完成后控制台会显示结果。
如图,左侧显示结果,绿色表示通过,红色或黄色失败,中间的那个表示忽略。右侧有详细失败信息,如期望值和实际值等。