JUnit单元测试6—@Rule注解
2019-09-26 本文已影响0人
莫问君心
JUnit Rule的两个注解需要用于实现了TestRule
或MethodRule
接口的成员变量(@Rule
)或静态变量(@ClassRule
)上。
-
@Rule
注解是方法级别的,每个测试方法执行时都会执行被@Rule
注解的成员变量的方法(类似于@Before
)。 -
@ClassRule
注解是类级别的,测试类执行时仅会执行一次被@ClassRule
注解的静态变量的方法(类似于@BeforeClass
)。
JUnit Rule和@Before注解的区别
@Before
注解的方法只能作用于当前测试类及其子类,而实现了TestRule
的类可以被用于多个测试类,因此JUnit Rule可以降低代码重复度并且更灵活。
JUnit Rule可以实现@Before, @BeforeClass, @After, @AfterClass
的所有功能,并且会更强大:
- 多个不同的rule对象用于同一个测试用例时,测试人员可以使用
RuleChain
来设定这些rule的执行先后顺序。 - JUnit Rule提供了多个实用的内置Rule:
- ExpectedException:支持在测试中指定期望抛出的异常类型,类似于
@Test(expected = xxxException.class)
。 - ExternalResource:支持提前建立好资源并且会在测试结束后将其销毁,这对于使用Socket、数据库链接等资源的测试来说很有用。
- TemporaryFolder:支持创建文件与目录并且在测试运行结束后将其删除,这对于使用文件系统且独立运行的测试来说很有用。
- TestName:支持在测试中获取当前测试方法的名称。
- TestWatcher:提供五个触发点:
测试开始、测试完成、测试成功、测试跳过、测试失败
,允许我们在每个触发点执行自定义的逻辑。 - Timeout:支持为测试类中的所有测试方法设置相同的超时时间,类似于
@Test(timeout = 100)
。
- ExpectedException:支持在测试中指定期望抛出的异常类型,类似于
内置Rule使用示例:
- TemporaryFolder示例:
// 使用系统临时目录,可在构造方法上加入路径参数来指定临时目录
@Rule
public TemporaryFolder tempFolder = new TemporaryFolder();
@Test
public void testTempFolderRule() throws IOException {
// 在系统的临时目录下创建文件或者目录,当测试方法执行完毕自动删除
tempFolder.newFile("test.txt");
tempFolder.newFolder("test");
}
- Timeout示例:
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
public class TimeoutTest {
@Rule
public Timeout timeout = new Timeout(1000);
// 测试失败
@Test
public void test1() throws Exception {
Thread.sleep(1001);
}
// 测试成功
@Test
public void test2() throws Exception {
Thread.sleep(999);
}
}
自定义Rule
自定义的Rule只需实现TestRule接口,并实现其中apply()方法即可,该方法返回一个Statement对象。
下面展示一个用于循环调用测试方法的Rule,该类中的base.evaluate();
用于继续运行测试方法。
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
public class LoopRule implements TestRule {
private int loopCount;
public LoopRule(int loopCount) {
this.loopCount = loopCount;
}
@Override
public Statement apply(Statement base, Description desc) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
for (int i = 1; i <= loopCount; i++) {
System.out.println("Loop " + i + " started");
base.evaluate();
System.out.println("Loop " + i + " finished\n----------------");
}
}
};
}
}
测试类:
import org.junit.Rule;
import org.junit.Test;
public class HelloWorldTest {
@Rule
public LoopRule loopRule = new LoopRule(2);
@Test
public void testSayHello() {
System.out.println("helloWorld");
}
}
测试输出结果:
Loop 1 started
helloWorld
Loop 1 finished
----------------
Loop 2 started
helloWorld
Loop 2 finished
----------------