一、基础规则
Rules【规则】允许在测试类中非常灵活的增加或重新定义每个测试方法的行为。测试人员可以重用或拓展下面提供的规则或编写自己的规则。
简单来说就是提供了测试用例在执行过程中通用功能的共享的能力,使我们不必重复编写一些功能类似的代码。
JUnit用于标注规则的注解包括@Rule
和@ClassRule
,区别在于作用域不同:
- @Rule的作用域是测试方法,每个测试方法执行时都会调用被注解的Rule
- @ClassRule的作用域是测试类,在执行一个测试类的时候只会调用一次被注解的Rule
我们在使用规则的时候需要使用@Rule
注解进行注释,被该注解注释的类实例需要是TestRule
接口的实现,且作用于该类中的所有测试方法。
TestRule接口的实现:
TemporaryFolder
:创建新文件,并在测试后删除ExternalResource
:例如,启动和停止服务器ErrorCollector
: 在一个测试方法中收集多个错误Verifier
:如果对象状态不正确,则测试失败TestWatcher
: 在方法执行期间添加事件的逻辑TestName
: 记住在方法中使用的测试名称Timeout
:使测试在设定的时间后失败ExpectedException
:抛出异常的灵活断言
JUnit Rule主要包含三要素,运行测试的语句、选择需要运行哪些语句的规则以及@Rule标记。
在加入了@Rule
后JUnit按如下流程运行测试:
- 创建默认语句运行测试
- 找出测试类中所有的标记了
@Rule
的public的成员规则 - 调用Rule中的
apply()
方法并告诉该方法所要运行的测试类和测试方法以及JUnit所收集到的语句。apply()方法决定怎么来运行测试,选择或者创建语句来运行测试并返回相应的语句传给JUnit。然后JUnit把语句传给下一个rule的apply方法,如此循环直到最后一条规则。 - 调用最后一条Rule返回的语句的
evaluate()
来运行测试
1.1 TemporaryFolder
TemporaryFolder
规则允许创建文件或文件夹,在测试方法(无论是通过还是失败)执行完成时会被删除。默认情况下,如果资源无法被删除是不会抛出异常的:
public static class HasTempFolder {
@Rule
public final TemporaryFolder folder = new TemporaryFolder();
@Test
public void testUsingTempFolder() throws IOException {
File createdFile = folder.newFile("myfile.txt");
File createdFolder = folder.newFolder("subfolder");
// ...
}
}
TemporaryFolder#newFolder(String... folderNames)
会递归的创建一个临时文件夹。TemporaryFolder#newFile()
创建一个随机名称的文件, 同样#newFolder()
创建一个随机名称的文件夹
示例:
public class FileWriter {
public void writeTo(String path, String content) throws IOException {
Path target = Paths.get(path);
if (Files.exists(target)) {
throw new IOException("file already exists");
}
Files.copy(new ByteArrayInputStream(content.getBytes("UTF8")), target);
}
}
//依赖于AssertJ
import static org.assertj.core.api.Assertions.assertThat;
public class FileWriterTest {
private FileWriter fileWriter = new FileWriter();
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void throwsErrorWhenTargetFileExists() throws IOException {
// arrange
File output = temporaryFolder.newFile("output.txt");
thrown.expect(IOException.class);
thrown.expectMessage("file already exists");
// act
fileWriter.writeTo(output.getPath(), "test");
}
@Test
public void writesContentToFile() throws IOException {
// arrange
File output = temporaryFolder.newFolder("reports")
.toPath()
.resolve("output.txt")
.toFile();
// act
fileWriter.writeTo(output.getPath(), "test");
// assert
assertThat(output)
.hasContent("test")
.hasExtension("txt")
.hasParent(resolvePath("reports"));
}
private String resolvePath(String folder) {
return temporaryFolder
.getRoot().toPath()
.resolve(folder)
.toString();
}
}
1.2 ExternalResource
ExternalResource
是规则TemporaryFolder
的基础类【是一个抽象类】,在测试之前建立一个外部资源(一个文件,套接字[socket],服务[server],数据库连接,等等),并且保证最后将其关闭。
public static class UsesExternalResource {
Server myServer = new Server();
@Rule
public final ExternalResource resource = new ExternalResource() {
@Override
protected void before() throws Throwable {
myServer.connect();
};
@Override
protected void after() {
myServer.disconnect();
};
};
@Test
public void testFoo() {
new Client().run(myServer);
}
}
1.3 ErrorCollector
ErrorCollector
规则允许在第一个问题发现之后继续运行(例如,收集下面不正确的行到一个表中,然后一次性报告所有错误。)
public static class UsesErrorCollectorTwice {
@Rule
public final ErrorCollector collector = new ErrorCollector();
@Test
public void example() {
collector.addError(new<