JUnit4用到了许多Java 5中的特性,如注解、泛型和静态导入等。所以在使用JUnit4时,JDK必须是Java 5或者更高的版本。
JUnit4的maven依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
1、测试类的定义
相比于需要继承 junit.frameworkTestCase 类的JUnit3,基于注解的JUnit4在使用上无疑要更加地便捷。
对于测试类的定义,JUnit4只要求测试类是公共的并且包含一个无参构造器;而对于具体的测试方法,则要求其使用 @Test 进行注解,并且是公共的、不带有任何参数、没有返回值的(返回值类型为void)。
示例:
import org.junit.Test;
/**
* Created by zhangcs on 17-4-22.
* 测试类
* 定义要求:访问权限必须是public
*/
public class ExampleTest {
/**
* 测试方法
* JUnit在调用该方法前会创建一个新的实例
* 定义要求:
* 1、访问权限必须是public
* 2、没有参数列表
* 3、返回值类型为void
**/
@Test
public void testMethod(){
// 测试内容
}
}
这是一个简单的测试类,因为我们并没有定义任何的构造器,所以Java会隐式创建一个无参构造器。需要注意的是,公共构造器只能有一个,如果存在多个公共构造器,JUnit将会抛出一个错误
java.lang.IllegalArgumentException: Test class can only have one constructor
虽然 JUnit 并没有对类名进行要求,但是因为通常在生产类和测试类之间都存在着一对一的对应关系,所以对于测试类我们一般都会遵循以待测试类名 + Test为前缀或后缀 进行命名,测试方法则使用 test前缀 + 待测方法名 + [后缀] 进行命名,测试方法的后缀用来在多个方法同名时进行区分。
这样命名的好处在于你能够通过名称来了解到这个测试类或方法是用来测试什么的。
2、断言
当然,仅仅定义测试类和测试方法是没有任何意义的。为了进行测试验证,我们还需要使用JUnit的断言来检测被测方法是否符合我们的预期。
断言,其实就是一些用来帮助我们确定被测试的方法是否按照预期的效果正常工作的辅助函数。JUnit中的断言可以使用 org.junit.Assert 类的assert方法。
示例:
@Test
public void testMethod(){
double sum = 1 + 1;
// 断言变量sum等于2
assertEquals( "sum不等于2",2, sum);
}
常用assert方法:
assertXXX 方法 | 说明 |
---|---|
assertEquals( “message”, A, B) | 断言A对象和B对象相等。在进行比较时使用了equals()方法,断言不通过时将会显示message信息,message可省(不建议省略) |
assertSame( “message”, A, B) | 断言A对象和B对象相同。进行比较时判断的是是否为同一个对象(使用==进行判断) |
assertArrayEquals( “message”, A, B) | 断言A数组和B数组相等。进行比较时判断的是数组内容是否相同 |
assertTrue( “message”, A) | 断言A条件为真 |
assertNotNull( “message”, A) | 断言A对象不为null |
异常测试
有些时候,我们可能想知道某些特定的情况下方法是否会抛出相应错误。如果使用assert方法进行检测,可以通过 try/catch 块捕获异常然后再使用assertEquals()方法断言预期的异常
@Test
public void testMethodIOException(){
try{
// 调用需要进行测试的方法,这里为了更直观直接抛出异常
throw new IOException();
}catch( Exception e){
assertEquals( "IOException", e.getClass().getSimpleName());
}
}
显然,这种做法并不十分可取,大的 try/catch 块不利于我们对测试方法进行维护。我们可以通过指定 @Test 注解的 expected 属性的方式进行检测, expected 属性的值为具体的异常类型。
示例:
为了方便演示,这里定义一个需要被测试的计算类Calculator
public class Calculator{
// 返回两个数相除的结果
public int division( int num1, int num2){
return num1 / num2;
}
}
我们知道,在Java中当两个int类型的值相除时,除数为0将会抛出 ArithmeticException 异常。所以这里我们可以为@Test的expected属性指定具体的异常类型 ArithmeticException.class 来进行检测
public class CalculatorTest {
// 当方法抛出ArithmeticException异常时检测通过
@Test( expected = ArithmeticException.class)
public void testDivisionArithmeticException(){
Calculator mc = new Calculator();
int num = mc.division( 2, 0);
}
}
超时测试
在性能较为敏感的系统里,我们往往需要确保功能在给定的时间内执行完。JUnit为我们提供了@Test的另一个属性:timeout 对执行时间进行检测
使用timeout指定以毫秒为单位的时间,如果测试方法超出该时间仍然未执行完成,那么JUnit就会将这个方法记为失败
示例:
指定测试方法执行时间为1000毫秒,当实际执行时间超出时将会被记为失败
@Test( timeout = 1000)
public void testTimeOut() throws InterruptedException {
// 调用方法,这里为了更直观直接让线程等待2000毫秒
Thread.sleep( 2000);
}
3、跳过测试
当测试方法暂时不需要时,我们可以使用@Ignore注解来跳过测试方法。@Ignore注解的value属性能够添加跳过测试的说明,说明为什么要跳过该测试。
@Ignore( value = "这里是忽略信息,添加了该注解的方法将不会被执行")
@Test( timeout = 1000)
public void testTimeOut() throws InterruptedException {
// 调用方法,这里为了更直观直接让线程等待2000毫秒
Thread.sleep( 2000);
}
4、运行测试
运行测试时我们需要先对测试类进行编译,然后再运行
# 编译
javac -cp /opt/junit/junit4.12/junit4.12.jar *.java
# 执行
java -cp .://opt/junit/junit4.12/junit4.12.jar org.junit.runner.JUnitCore XXXTest
这样对类进行测试十分的麻烦,所幸的是当前大部分IDE和构建工具都对JUnit进行了集成,我们可以直接从IDE或者构建工具快速运行测试。
JUnit测试在大部分的IDE操作上都是类似的。idea上可以直接运行测试类,或者选择测试类或方法所在行行号旁边的小绿点执行测试,甚至是直接以运行Java Application的方式运行测试类;eclipse则需要选中测试类或者测试方法,右击选中“Run AS —Run Test”执行测试
不论是idea还是eclipse,都会显示测试类信息和一条测试状态条。在所有的测试方法断言均通过时,测试状态条将会变为绿色,并在左下方显示具体哪些类、方法被测试并且通过了
在测试方法不通过时,进度条将显示为红色,并打印对应的信息