前言 本文将快速介绍如何在JUnit
测试框架中使用自定义Runner
来运行单测 当前, 这需要配合@RunWith
注解
准备 首先, 添加项目依赖
1 2 3 4 5 <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12 </version> </dependency>
实现Runner JUnit框架提供了抽象类Runner
, 它定义了两个抽象方法
1 2 3 public abstract Description getDescription () ;public abstract void run (RunNotifier var1) ;
另外, 它还需要实现Describable
接口, 即实现getDescription()
方法 接下来我们实现一个CustomerRunner
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 import org.junit.Test;import org.junit.runner.Description;import org.junit.runner.Runner;import org.junit.runner.notification.RunNotifier;import java.lang.reflect.Method;public class CustomerRunner extends Runner { private Class testedClass; public CustomerRunner (Class testedClass) { super (); this .testedClass = testedClass; } @Override public Description getDescription () { return Description.createTestDescription(testedClass, "A Customer runner" ); } @Override public void run (RunNotifier notifier) { System.out.println("running the tests based on CustomerRunner" + testedClass); try { Object testedObject = testedClass.newInstance(); for (Method method : testedClass.getMethods()) { if (method.isAnnotationPresent(Test.class)) { notifier.fireTestStarted(Description.createTestDescription(testedClass, method.getName())); method.invoke(testedObject); notifier.fireTestFinished(Description.createTestDescription(testedClass, method.getName())); } } } catch (Exception e) { throw new RuntimeException (e); } } }
在这个实现类中, 我们定义了一个接受类参数的构造函数, 这是JUnit框架对Runner的规范. 单测运行时, JUnit会将目标类传给Runner的构造器.getDescription
方法用于返回描述信息, 而最关键的就在于run
方法实现, 通过反射来调用目标方法. 另外, 通过run
方法的入参RunNotifier
, 我们可以出发具有各种测试进度信息的事件. 这里我们仅在目标方法调用前后触发事件. 感兴趣的话可以自行翻下RunNotifier中定义的其他方法
接下来, 我们随便写个测试用例来用下这个Runner
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import org.junit.Test;import org.junit.runner.RunWith;import static org.junit.Assert.*;@RunWith(CustomerRunner.class) public class CustomerRunnerTest { Calculator calculator = new Calculator (); @Test public void testCalculator () { System.out.println("start Calculator" ); assertEquals("addition" , 8 , calculator.add(5 , 3 )); } } class Calculator { public int add (int a, int b) { return a + b; } }
Runner
是JUnit中的低级运行器, 相比之下, 其子类ParentRunner
和BlockJUnit4Runner
更加易于定制和扩展ParentRunner
同样是个抽象类, 它会以分层的方式来运行测试 一般情况, 如果你想对Runner做定制, 从BlockJUnit4Runner
来派生子类是不错的选择
小结 通过定制JUnit Runner, 开发人员可以自由控制测试执行的整个过程. 一些流行的第三方Runner实现还有SpringJUnit4ClassRunner
, MockitoJUnitRunner
, HierarchicalContextRunner
等 如果你想runwith multiple runner, 可以考虑从多个父类派生出新的子类Runner 而在PowerMock中, 这个问题是通过代理的方式解决的(@PowerMockRunnerDelegate
), 也是个不错的思路