Rules

我们之前处理异常的时候用到过Rules,当然还有很多其他规则。Rules允许弹性的添加或者重定义测试方法的行为。测试者可以重复使用或者扩展下面的某一个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!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值