规则容许在测试类中对每一个测试方法的行为进行很是灵活的添加或从新定义。测试人员能够重用或扩展所提供的规则之一,或者编写本身的规则。html
对于一个规则使用的例子,能够使用临时文件夹和预期功能来进行测试:java
public class DigitalAssetManagerTest { @Rule public final TemporaryFolder tempFolder = new TemporaryFolder(); @Rule public final ExpectedException exception = ExpectedException.none(); @Test public void countsAssets() throws IOException { File icon = tempFolder.newFile("icon.png"); File assets = tempFolder.newFolder("assets"); createAssets(assets, 3); DigitalAssetManager dam = new DigitalAssetManager(icon, assets); assertEquals(3, dam.getAssetCount()); } private void createAssets(File assets, int numberOfAssets) throws IOException { for (int index = 0; index < numberOfAssets; index++) { File asset = new File(assets, String.format("asset-%d.mpg", index)); Assert.assertTrue("Asset couldn't be created.", asset.createNewFile()); } } @Test public void throwsIllegalArgumentExceptionIfIconIsNull() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Icon is null, not a file, or doesn't exist."); new DigitalAssetManager(null, null); } }
TemporaryFolder Rule容许的临时文件夹的文件和文件夹,删除时,测试方法完成创做(不管经过或失败)。默认状况下,若是资源不能删除,则不会引起异常:git
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"); // ... } }
ExternalResource 是一个基于Rule 的类,他能在测试开始以前设置一些资源,其实就是相似@Before , 不过就是换了Rule来实现而已。app
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); } }
Errorcollector规则容许一个测试后的第一个问题是发现继续执行(例如,收集在一个表中,全部错误的行和报告一次):ide
public static class UsesErrorCollectorTwice { @Rule public final ErrorCollector collector = new ErrorCollector(); @Test public void example() { collector.addError(new Throwable("first thing went wrong")); collector.addError(new Throwable("second thing went wrong")); } }
Verifier Rule像Errorcollector基类,能够将本来经过测试方法测试失败若是验证检查失败。oop
private static String sequence; public static class UsesVerifier { @Rule public final Verifier collector = new Verifier() { @Override protected void verify() { sequence += "verify "; } }; @Test public void example() { sequence += "test "; } @Test public void verifierRunsAfterTest() { sequence = ""; assertThat(testResult(UsesVerifier.class), isSuccessful()); assertEquals("test verify ", sequence); } }
import static org.junit.Assert.fail; import org.junit.AssumptionViolatedException; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; import org.junit.runners.model.Statement; public class WatchmanTest { private static String watchedLog; @Rule public final TestRule 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() { } }
The TestName Rule makes the current test name available inside test methods:测试
public class NameRuleTest { @Rule public final TestName name = new TestName(); @Test public void testA() { assertEquals("testA", name.getMethodName()); } @Test public void testB() { assertEquals("testB", name.getMethodName()); } }
The Timeout Rule applies the same timeout to all test methods in a class:ui
public static class HasGlobalTimeout { public static String log; @Rule public final TestRule globalTimeout = Timeout.millis(20); @Test public void testInfiniteLoop1() { log += "ran1"; for(;;) {} } @Test public void testInfiniteLoop2() { log += "ran2"; for(;;) {} } }
The ExpectedException Rule allows in-test specification of expected exception types and messages:this
public static class HasExpectedException { @Rule public final ExpectedException thrown = ExpectedException.none(); @Test public void throwsNothing() { } @Test public void throwsNullPointerException() { thrown.expect(NullPointerException.class); throw new NullPointerException(); } @Test public void throwsNullPointerExceptionWithMessage() { thrown.expect(NullPointerException.class); thrown.expectMessage("happened?"); thrown.expectMessage(startsWith("What")); throw new NullPointerException("What happened?"); } }
The ClassRule annotation extends the idea of method-level Rules, adding static fields that can affect the operation of a whole class. Any subclass of ParentRunner, including the standard BlockJUnit4ClassRunner and Suite classes, will support ClassRules.lua
For example, here is a test suite that connects to a server once before all the test classes run, and disconnects after they are finished:
@RunWith(Suite.class) @SuiteClasses({A.class, B.class, C.class}) public class UsesExternalResource { public static final Server myServer = new Server(); @ClassRule public static final ExternalResource resource = new ExternalResource() { @Override protected void before() throws Throwable { myServer.connect(); }; @Override protected void after() { myServer.disconnect(); }; }; }
The RuleChain rule allows ordering of TestRules:
public static class UseRuleChain { @Rule public final TestRule chain = RuleChain .outerRule(new LoggingRule("outer rule")) .around(new LoggingRule("middle rule")) .around(new LoggingRule("inner rule")); @Test public void example() { assertTrue(true); } }
Most custom rules can be implemented as an extension of the ExternalResource rule. However, if you need more information about the test class or method in question, you'll need to implement the TestRule interface.
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; } }
Of course, the power from implementing TestRule comes from using a combination of custom constructors, adding methods to the class for use in tests, and wrapping the provided Statement in a new Statement. For instance, consider the following test rule that provides a named logger for every test:
package org.example.junit; 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()); base.evaluate(); } }; } }
Then that rule could be applied like so:
import java.util.logging.Logger; import org.example.junit.TestLogger; import org.junit.Rule; import org.junit.Test; public class MyLoggerTest { @Rule public final TestLogger logger = new TestLogger(); @Test public void checkOutMyLogger() { final Logger log = logger.getLogger(); log.warn("Your test is showing!"); } }