第一次写源代码分析,介绍运行流程和其中重要的类和接口!
JUnitCore
JUnitCore采用门面模式,可以启动junit4,junit3测试,也可以测试指定class。JUnitCore声明RunNotifier类,该类采用观察者模式实现事件管理。RunListener为测试事件基类,有测试开始结束失败等事件,如果想自定义事件可以继承该类。默认增加了两个RunListener,一个是TextListener,另一个是Result类函数createListener构造的Listener用于记录开始结束时间、执行总数、失败总数等。可看到run方法调用前触发了fireTestRunStarted,执行后触发了fireTestRunFinished。关键代码(截取)
private final RunNotifier notifier = new RunNotifier(); Result runMain(JUnitSystem system, String... args) { RunListener listener = new TextListener(system); addListener(listener); return run(jUnitCommandLineParseResult.createRequest(defaultComputer())); } public Result run(Request request) { return run(request.getRunner()); } public Result run(Runner runner) { Result result = new Result(); RunListener listener = result.createListener(); notifier.addFirstListener(listener); try { notifier.fireTestRunStarted(runner.getDescription()); runner.run(notifier); notifier.fireTestRunFinished(result); } finally { removeListener(listener); } return result; }
Request
对class和test的封装,可以是一个class下所有test、所有class下所有test、还可以结合filter。classes方法获取suite,suite里包含各个类的runner。关键代码(截取)
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"); } }
RunnerBuilder
创建runner采用builder模式,对于每一个class产生一个runner。
private List<Runner> runners(Class<?>[] children) { ArrayList<Runner> runners = new ArrayList<Runner>(); for (Class<?> each : children) { Runner childRunner = safeRunnerForClass(each); if (childRunner != null) { runners.add(childRunner); } } return runners; }
AllDefaultPossibilitiesBuilder
选择具体builder,默认为junit4Builder,如果class有@Ignore标注则为IgnoredBuilder,如果class有@RunWith标注则为IgnoredBuilder,如果测试方法有suite则为SuiteMethodBuilder,如果class继承于junit.framework.TestCase则为JUnit38ClassRunner,否则默认时用JUnit4Builder返回BlockJUnit4ClassRunner
public Runner runnerForClass(Class<?> testClass) throws Throwable { List<RunnerBuilder> builders = Arrays.asList( ignoredBuilder(), annotatedBuilder(), suiteMethodBuilder(), junit3Builder(), junit4Builder()); for (RunnerBuilder each : builders) { Runner runner = each.safeRunnerForClass(testClass); if (runner != null) { return runner; } } return null; }