在junit4X之前的版本,测试的API都是基于继承junit.framework.TestCase的测试类,所以扩展junit要覆盖某些继承行为。junit4X系列之后junit采用注解的方式,所以我们来扩展junit的时候也就多了一种选择。
扩展内置的junit行为的主要相关概念是运行器和规则。尽管我们不大会深入自定义插件,但是我们还是应该意识到哪些插件是内置的,以及如何开始编写自定义插件。
从上一篇博客中,我们也看出来了,实现自定义运行器不是一件小事,所有出于这个原因,我们更倾向于自定义规则。所以这篇博客的内容主要集中于junit的规则是如何工作的,以及那些规则是我们可以开箱即用的。
规则是最近才加到junit中的,它能操纵测试的执行。比如,规则的实现能跳过整个执行,或在测试运行前后来执行一些setup或teardown。规则是应用到类这以及,你可以对一个雷应用多条规则。
多条规则的情况下,每次会应用一条。注意的是:junit并不保证应用规则的顺序。
junit观察一个测试类时,它会为运行每个找到的测试建立一个执行计划。规则,即org.junit.rules.MethodRule的实现,基本上会封装或代替当前的执行计划。
OK,现在让我们来看一看那些是内置的规则。
junit没有将规则API作为一个扩展点来提供给用户,大量基础的junit都是用同样的API实现的,包括整个测试类的全局超时,处理期望异常的复杂方式,以及临时文件系统资源的管理。
- 1,配置全局超时
package org.linkinpark.junit.testjunit;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;
/**
* @创建作者: LinkinPark
* @创建时间: 2016年2月16日
* @功能描述: 全局超时的一个例子
*/
public class GlobalTimeoutTest
{
@Rule
public Timeout globalTimeout = Timeout.millis(20);
@Test
public void test()
{
Assert.assertEquals("1", "1");
}
@Test
public void run1() throws InterruptedException
{
Thread.sleep(100);
}
@Test
public void infiniteLoop()
{
while (true)
{
}
}
}
关于上面的代码,我这里解释一下如何配置全局超时:
1,定义一个MethodRule类型的属性
2,该属性用@Rule注解修饰
3,属性的名字倒是无所谓,一般按照实际的意义来命名就好了。
上面的代码中我自己写了3个测试,其中有2个测试的执行时间都超出了20秒,所以2个测试失败。junit控制台输出如下:
- 2,预期的异常
当然我们也可以使用try和catch来捕获异常,然后使用hamcrest匹配异常信息。
这里在介绍一种相对比较复杂的规则,就是使用expectedException规则来测试异常的信息,根因。代码如下:
package org.linkinpark.junit.testjunit;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
/**
* @创建作者: LinkinPark
* @创建时间: 2016年2月16日
* @功能描述: expectedException规则的一个例子
*/
public class SimpleExpectedExceptionTest
{
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void throwsNothing()
{
// no exception expected, none thrown: passes.
}
/**
* @创建时间: 2016年2月16日
* @相关参数:
* @功能描述: 单纯的测试抛出异常的类型
*/
@Test
public void throwsExceptionWithSpecificType()
{
thrown.expect(NullPointerException.class);
throw new NullPointerException();
}
/**
* @创建时间: 2016年2月16日
* @相关参数:
* @功能描述: 测试抛出的异常类型+异常信息
*/
@Test
public void throwsExceptionWithCorrectMessage()
{
thrown.expect(RuntimeException.class);
thrown.expectMessage("LinkinPark");
throw new RuntimeException("LinkinPark。。。");
}
}
3,临时文件夹
大多数单元测试应对远离文件系统,但时不时会要编写一个自动的,可重复的,与文件系统中的文件打交道的测试。这就是最后一个规则的用武之地。
TemporaryFolder是个简单的工具,利用它我们可以容易的在测试中创建临时文件和文件夹,并令其在测试运行之后自动消失。
package org.linkinpark.junit.testjunit;
import java.io.File;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
/**
* @创建作者: LinkinPark
* @创建时间: 2016年2月16日
* @功能描述: 创建临时文件夹的一个例子
*/
public class HasTempFolder
{
@Rule
public TemporaryFolder folder = new TemporaryFolder();
@Test
public void testUsingTempFolder() throws IOException
{
// 创建临时文件
File createdFile = folder.newFile("myfile.txt");
// 创建临时文件夹
File createdFolder = folder.newFolder("subfolder");
System.out.println(createdFile.getAbsolutePath());
System.out.println(createdFolder.getPath());
Assert.assertTrue(createdFile.exists());
Assert.assertTrue(createdFolder.exists());
}
}