Junit测试用例均是以JunitCore.run(Class<?> class)开始的,接下来分析一下,Junit是怎么触发用例执行的
1.获取Runner
public Result run(Class<?>... classes) {
return run(defaultComputer(), classes);
}
入参为Class对象,代表承载测试用例的测试类,继续分析run(defaultComputer(), classes),重点分析一下Computer.class,其代码如下
public class Computer {
15 /**
16 * Returns a new default computer, which runs tests in serial order
17 */
18 public static Computer serial() {
19 return new Computer();
20 }
21
22 /**
23 * Create a suite for {@code classes}, building Runners with {@code builder}.
24 * Throws an InitializationError if Runner construction fails
25 */
26 public Runner getSuite(final RunnerBuilder builder,
27 Class<?>[] classes) throws InitializationError {
28 return new Suite(new RunnerBuilder() {
29 @Override
30 public Runner runnerForClass(Class<?> testClass) throws Throwable {
31 return getRunner(builder, testClass);
32 }
33 }, classes);
34 }
35
36 /**
37 * Create a single-class runner for {@code testClass}, using {@code builder}
38 */
39 protected Runner getRunner(RunnerBuilder builder, Class<?> testClass) throws Throwable {
40 return builder.runnerForClass(testClass);
41 }
42}
此类比较简单,包括三个函数
- serial():静态接口,反馈Computer对象,功能类似构造函数
- getSuite():获取指定测试类集合的Runner信息,suite代码测试类集合,一个测试类集合中包含多个测试类
- getRunner():获取指定测试类的Runner
由此可见,此类的主要功能是获取测试用例的Runner,这三个函数在此不详细介绍,在下边的章节进行分析
public Result run(Computer computer, Class<?>... classes) {
return run(Request.classes(computer, classes));
}
接着嵌套调用run(Request request),继续分析Request类
junit/src/main/java/org/junit/runner/Request.java
public static Request classes(Computer computer, Class<?>... classes) {
try {
AllDefaultPossibilitiesBuilder builder = new AllDefaultPossibilitiesBuilder(true);
Runner suite = computer.getSuite(builder, classes);
return runner(suite);
} catch (InitializationError e) {
throw new RuntimeException(
"Bug in saff's brain: Suite constructor, called as above, should always complete");
}
}
通过静态方法classes构造Request对象,那classes干了什么呢?
AllDefaultPossibilitiesBuilder
首先,构造RunnerBuilder对象,从名字可以看出,这个对象是用例生成runner的,AllDefaultPossibilitiesBuilder是
RunnerBuilder的子类,RunnerBuilder是个抽象类,其规定了解析Runner的一些基本规则,其子类需实现
runnerForClass方法,那我们具体看一下AllDefaultPossibilitiesBuilder做了什么
public class AllDefaultPossibilitiesBuilder extends RunnerBuilder {
10 private final boolean canUseSuiteMethod;
11
12 public AllDefaultPossibilitiesBuilder(boolean canUseSuiteMethod) {
13 this.canUseSuiteMethod = canUseSuiteMethod;
14 }
15
16 @Override
17 public Runner runnerForClass(Class<?> testClass) throws Throwable {
18 List<RunnerBuilder> builders = Arrays.asList(
19 ignoredBuilder(),
20 annotatedBuilder(),
21 suiteMethodBuilder(),
22 junit3Builder(),
23 junit4Builder());
24
25 for (RunnerBuilder each : builders) {
26 Runner runner = each.safeRunnerForClass(testClass);
27 if (runner != null) {
28 return runner;
29 }
30 }
31 return null;
32 }
33
34 protected JUnit4Builder junit4Builder() {
35 return new JUnit4Builder();
36 }
37
38 protected JUnit3Builder junit3Builder() {
39 return new JUnit3Builder();
40 }
41
42 protected AnnotatedBuilder annotatedBuilder() {
43 return new AnnotatedBuilder(this);
44 }
45
46 protected IgnoredBuilder ignoredBuilder() {
47 return new IgnoredBuilder();
48 }
49
50 protected RunnerBuilder suiteMethodBuilder() {
51 if (canUseSuiteMethod) {
52 return new SuiteMethodBuilder();
53 }
54 return new NullBuilder();
55 }
56}
AllDefaultPossibilitiesBuilder的构造函数很简单,只是透传了canUseSuiteMethod,其代码是否要查找SuiteMethod,我们重点看一下runnerForClass,如何找到合适的Runner。runnerForClass首先,建立了一个数组,其中包含5和RunnerBuilder,分别为:IgnoredBuilder:查找测试类否有Ignore注解AnnotatedBuilder:解析测试类的RunWith注解,生成Runner,此Runner可以是Junit自带的,也可以是自定义的,会在后续文章中介绍如何自定义RunerSuiteMethodBuilder:查找测试类中是否有SuiteRunnerJUnit3Builder:如果是使用Junit4之前的语法编写的测试类,返回JUnit38ClassRunnerJUnit4Builder:返回BlockJUnit4ClassRunner,即Junit4默认的Runner然后,遍历Runner列表,找到合适的Runner后就返回Computer.getSuite在此详细分析一下getSuite干了什么
public Runner getSuite(final RunnerBuilder builder,
27 Class<?>[] classes) throws InitializationError {
28 return new Suite(new RunnerBuilder() {
29 @Override
30 public Runner runnerForClass(Class<?> testClass) throws Throwable {
31 return getRunner(builder, testClass);
32 }
33 }, classes);
34 }
Suite的构造函数有两个入参,分别是RunnerBuilder和Class,Class无需多讲,重点看RunnerBuilder是如何构造的。
new 一个RunnerBuilder,并实现了runnerForClass,调用Computer.getRunner(RunnerBuilder, Class),在此能接上上边分析的AllDefaultPossibilitiesBuilder.runnerForClass,获取所有测试类的Runner集合。
至此,已经获取到了执行用例的Runner,接下来就是执行用例了
执行测试用例
public Result run(Runner runner) {
132 Result result = new Result();//实例化Result类,用于保存用例执行结果
133 RunListener listener = result.createListener();//新建执行监听器,用于监听用例执行的状态,如pass、fail、ignore
134 notifier.addFirstListener(listener);//设置监听器
135 try {
136 notifier.fireTestRunStarted(runner.getDescription());//开始执行用例
137 runner.run(notifier);//执行用例
138 notifier.fireTestRunFinished(result);//保存结果
139 } finally {
140 removeListener(listener);
141 }
142 return result;
143 }
在后续自定义Runner介绍的时候,再分析run的流程