Rules
这里先展示一张 TestRule的类图:
基本的规则有:
1.TemporaryFolder Rule
该规则建立的文件或者文件夹会在测试方法结束之后自动删除(不管测试pass还是fail)。默认情况下,即使资源删不掉也不会抛出异常。
import java.io.File; import java.io.IOException; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; public class RuleTest { @Rule public TemporaryFolder folder=new TemporaryFolder(); @Test public void test() throws IOException { File aFile=folder.newFile("myfile.txt"); File aFolder=folder.newFolder("subfolder"); } }
- TemporaryFolder#newFolder(String...folderNames) 会递归深入的新建多个文件夹。
- TemporaryFolder#newFile() 会新建一个带有随机名字的文件,#newFolder() 会新建一个带有随机名字的文件夹。
- 从 4.13开始,如果测试结束之后资源不能被删除, TemporaryFolder 可以选择允许测试以 AssertionError的方式fail。但是这个特性只有在使用 #builder()的方法才可以被激活。为了向后兼容默认情况下还是不会抛出异常。
@Rule
public TemporaryFolder folder=TemporaryFolder.builder().assureDeletion().build();
2.ExternalResource Rules
ExternalResource用来对外部资源进行管理,包括在测试之前进行外部资源准备,测试之后对测试资源进行回收等工作。在创建测试文件、连接服务器、准备数据库连接等情况下用的比较多。
import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExternalResource; public class RuleTest2 { @Rule public ExternalResource external = new ExternalResource() { protected void before() throws Throwable { System.out.println("Perparing test data."); System.out.println("Test data is Ready!"); } protected void after() { System.out.println("Cleaning test data."); } }; @Test public void test1() { System.out.println("Test 1 executing..."); } @Test public void test2() { System.out.println("Test 2 executing..."); } @Test public void test3() { System.out.println("Test 3 executing..."); } }
运行结果:
Perparing test data.
Test data is Ready!
Test 1 executing...
Cleaning test data.
Perparing test data.
Test data is Ready!
Test 2 executing...
Cleaning test data.
Perparing test data.
Test data is Ready!
Test 3 executing...
Cleaning test data.
3. ErrorCollector Rule
- 继承自下面的Verifier Rule。ErrorCollector 规则允许测试在第一个问题出现的时候继续执行,然后执行完之后一次性汇报结果。比如说测试一个表格里的所有的行,在第一行发现错误之后继续执行,直到所有 的错误都发现才停止,然后一次性汇报所有的结果。
import org.junit.Rule; import org.junit.Test; import org.junit.rules.ErrorCollector; public class TestRule3 { @Rule public ErrorCollector collector=new ErrorCollector(); @Test public void test() { collector.addError(new Throwable("first things went wrong!")); collector.addError(new Throwable("second things went wrong!")); } }
运行结果:
4. Verifier Rule
它是ErrorCollector的父类。当每个测试结束之后会执行ErrorCollector的verify方法,如果执行不通过这个测试会被标记为fail。
import static org.junit.Assert.*; import org.junit.Rule; import org.junit.Test; import org.junit.rules.Verifier; public class RuleTest4 { String sequence=""; @Rule public Verifier collector=new Verifier(){ @Override protected void verify(){ System.out.println("this is verify..."); assertEquals("test verify ",sequence); } }; @Test public void test01(){ System.out.println("this is testing 01..."); sequence += "test "; } @Test public void test02(){ System.out.println("this is testing 02..."); sequence="test verify "; } }
测试结果:
this is testing 01...
this is verify...
this is testing 02...
this is verify...
test01为 fail,而test02 pass。
5. TestWatchman/TestWatcher Rules
从4.9版本开始,TestWatcher开始代替 TestWatchman。TestWatcher实现了TestRule类,而不是MethodRule类。
TestWatchman从4.7版本开始引入,它使用 MethodRule,而MethodRule目前已经弃用。
TestWatcher 不会改变测试的任何行为,提供了 succeeded、failed、skipped、starting、finished方法用来监控一个测试方法生命周期的各个阶段,所有方法都包含一 个 org.junit.runner.Description 类型的参数用来描述当前执行的测试。
import static org.junit.Assert.*; import org.junit.AfterClass; import org.junit.Rule; import org.junit.Test; import org.junit.internal.AssumptionViolatedException; import org.junit.rules.TestWatcher; import org.junit.runner.Description; import org.junit.runners.model.Statement; public class RuleTest5 { private static String watchedLog=""; @Rule public TestWatcher watchman=new TestWatcher(){ @Override public Statement apply(Statement base,Description description){ return super.apply(base,description); } @Override protected void succeeded(Description description) { watchedLog += description.getDisplayName() + " " + "success!\n"; } @Override protected void failed(Throwable e, Description description) { watchedLog += description.getDisplayName() + " " + e.getClass().getSimpleName() + "\n"; } @Override protected void skipped(AssumptionViolatedException e, Description description) { watchedLog += description.getDisplayName() + " " + e.getClass().getSimpleName() + "\n"; } @Override protected void starting(Description description) { super.starting(description); } @Override protected void finished(Description description) { super.finished(description); } }; @Test public void fails() { fail(); } @Test public void succeeds(){ } @AfterClass public static void printlog(){ System.out.println(watchedLog); } }
测试结果:
succeeds(com.junit.org.RuleTest5) success!
fails(com.junit.org.RuleTest5) AssertionError
在每一条测试执行完之后,分别调用了 succeeded()和failed()方法对 watchedLog进行处理。当然我们还可以在监控方法里做一些其他的事情。
6. TestName Rule
有了这条规则,即使在测试方法内部我们也可以引用方法名。
import static org.junit.Assert.*; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestName; public class RuleTest6 { @Rule public TestName name=new TestName(); @Test public void testA(){ assertEquals("testA",name.getMethodName()); } @Test public void testB(){ assertEquals("testB",name.getMethodName()); } }
7. Timeout Rule
参考“七 Timeout for tests" 。
8. ExpectedException Rules
参考 ” 四 Exception testing"。
9. ClassRule
@ClassRule 注释扩展了方法级别的规则,它增加了一些静态属性,从而影响整个类。ParentRunner 的任何子类,包括 BlockJUnit4ClassRunner 和 Suite类,都支持 @ClassRule S.
比如说,将ExternalResource 从 @Rule 变成 @ ClassRule,则在整个类里的测试执行过程中它只会执行一次,也就是所有的测试类开始之前会执行 before(),所有的测试类执行结束之后会执行 after()。
import org.junit.ClassRule; import org.junit.rules.ExternalResource; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) @SuiteClasses({RuleTest.class,RuleTest2.class,RuleTest3.class}) public class TestSuite01 { @ClassRule public static ExternalResource resource= new ExternalResource() { @Override protected void before() throws Throwable { System.out.println("Before Class testing ......"); }; @Override protected void after() { System.out.println("After Class testing......"); }; }; }
测试执行结果:
Before Class testing ......
Test Method 1 executing...
Test Method 2 executing...
Test Method 3 executing...
After Class testing......
可以看到,整个过程中ClassRule只执行了一遍。
10 RuleChain
RuleChain 规则允许制定 TestRule的顺序。RuleChain提供一种将多个TestRule串在一起执行的机制,它首先从outChain()方法开始创建一个最外层的TestRule创建的Statement,而后调用round()方法,不断向内层添加TestRule创建的Statement。
public static class UseRuleChain { @Rule public TestRule chain= RuleChain .outerRule(new LoggingRule("outer rule")) .around(new LoggingRule("middle rule")) .around(new LoggingRule("inner rule")); @Test public void example() { assertTrue(true); } }
测试结果:
starting outer rule
starting middle rule
starting inner rule
finished inner rule
finished middle rule
finished outer rule
11 Custom Rules
扩展 ExternalResource 规则可以实现大部分需要个性化定制的规则。如果想要获取更过测试类的信息,则需要实现 TestRule接口。
import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; public class IdentityRule implements TestRule { @Override public Statement apply(final Statement base, final Description description) { return base; } }
上面只是一个简单的实现。我们还可以在实现TestRule接口的时候建立自己的构造器、添加测试方法、将提供的Statemetn包装成一个新的Statement。
TestRule的一个实现:
import java.util.logging.Logger; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; public class TestLogger implements TestRule { private Logger logger; public Logger getLogger() { return this.logger; } @Override public Statement apply(final Statement base, final Description description) { return new Statement() { @Override public void evaluate() throws Throwable { logger = Logger.getLogger(description.getTestClass().getName() + '.' + description.getDisplayName()); try { base.evaluate(); } finally { logger = null; } } }; } }
测试中使用:
import java.util.logging.Logger; import com.junit.org.TestLogger; import org.junit.Rule; import org.junit.Test; public class MyLoggerTest { @Rule public TestLogger logger = new TestLogger(); @Test public void checkOutMyLogger() { final Logger log = logger.getLogger(); log.warning("Your test is showing!"); } }
测试结果:
二月 03, 2015 4:59:34 下午 com.junit.org.MyLoggerTest checkOutMyLogger
警告: Your test is showing!