提个问题:Java程序的入口是main方法,而JUnit类中没有main方法,那么JUnit是如何运行的呢?
假如有以下JUnit例子:
import org.junit.Test;
public class TestA {
@Test
public void testAdd() {
System.out.println("A.testAdd");
}
}
一、在Eclipse中执行JUnit
在Eclipse中右键->Run As->JUnit Test,即可执行这个测试。如果在testAdd方法中打上断点(即第6行),我们来看下程序调用的栈:
可以看到,这个测试的JVM进程由RemoteTestRunner.main()方法启动,这个类是来自Eclipse的JUnit插件的,真正进入到JUnit的代码是BlockJUnit4ClassRunner.run(RunNotifier)。那么,Eclipse是如何开始调用BlockJUnit4ClassRunner的呢?
原来,在执行JUnit测试用例之前,Eclipse将会为这个测试类找到合适的Runner。看这段代码,这里给出了5种RunnerBuilder,它们会被按顺序依次遍历,找到一个合适的Runner后即停止:
- IgnoreBuilder。检查被测类是否含有@Ignore注解,如果有,则初始化一个IgnoredClassRunner,否则返回null。
- AnnotatedBuilder。检查被测类是否含有@RunWith注解,如果有,则用该注解的value初始化一个Runner,否则返回null。
- SuiteMethodBuilder。检查被测类是否含有一个叫“suite”的方法,如果有,则初始化一个SuiteMethod(这是JUnit3.8中使用的Runner),否则返回null。
- JUnit3Builder。检查被测类是否是TestCase的子类,如果是,则初始化一个JUnit38ClassRunner,否则返回null。
- JUnit4Builder。没有检查条件。将初始化一个BlockJUnint4ClassRunner。这也是JUnit4默认的Runner。
经过这5步,必然会找到一个Runner,我们这个了例子就会返回BlockJUnit4ClassRunner。接下来,我们看看这个JUnit4ClassRunner中发生了什么。
在上面已经提到,程序会在执行时会调用到BlockJUnit4ClassRunner.run方法,下面是在其父类ParentRunner类中的实现:
@Override
public void run(final RunNotifier notifier) {
EachTestNotifier testNotifier = new EachTestNotifier(notifier, getDescription());
try {
Statement statement = classBlock(notifier);
statement.evaluate(); // Would trigger the whole test case execution flow.
} catch (AssumptionViolatedException e) {
testNotifier.addFailedAssumption(e);
} c