TestNG与JUnit

Junit源码阅读笔记二(Runner构建)

2017-08-19  本文已影响44人  春狗

1.Runner

上一节讲到了Junit的运行实际上是调用Runner中的run方法执行的,那么接下来总结一下Runner,首先我们看下Runner的类图

Runner

2.Runner的构建

让我们回到类Request.class中的classes方法

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");
    }
}

由此可知第一个Runner是由computer.getSuite(builder, classes)中获得,参数builder是直接new AllDefaultPossibilitiesBuilder,从名称可以看出,这个builder是所有默认的可能builder,看起来很牛逼的样子,点进去可以发现构造方法只有一个属性赋值,先忽略,继续看computer.getSuite(builder, classes)

public Runner getSuite(final RunnerBuilder builder,
        Class<?>[] classes) throws InitializationError {

    return new Suite(new RunnerBuilder() {
        @Override
        public Runner runnerForClass(Class<?> testClass) throws Throwable {
            return getRunner(builder, testClass);
        }
    }, classes);
}

protected Runner getRunner(RunnerBuilder builder, Class<?> testClass) throws Throwable {
    return builder.runnerForClass(testClass);
}

由此可见这个Runner是直接new的一个Suite,进入 Suite类看该处调用的构造方法,

public Suite(RunnerBuilder builder, Class<?>[] classes) throws InitializationError {
    this(null, builder.runners(null, classes));
}
protected Suite(Class<?> klass, List<Runner> runners) throws InitializationError {
    super(klass);
    this.runners = Collections.unmodifiableList(runners);
}

继续看该方法中调用的runners方法

 private List<Runner> runners(Class<?>[] children) {
    ArrayList<Runner> runners = new ArrayList<Runner>();
    for (Class<?> each : children) {
        //循环遍历所有测试类的class,构建Runner
        //由此可以发现每个测试类对应一个Runner
        Runner childRunner = safeRunnerForClass(each);
        if (childRunner != null) {
            runners.add(childRunner);
        }
    }
    return runners;
}

继续看safeRunnerForClass方法

public Runner safeRunnerForClass(Class<?> testClass) {
    try {
        return runnerForClass(testClass);
    } catch (Throwable e) {
        return new ErrorReportingRunner(testClass, e);
    }
}
Suite创建时Builder的调用

3.RunnerBuilder

首先来看上文中调用的AllDefaultPossibilitiesBuilder.runnerForClass

public Runner runnerForClass(Class<?> testClass) throws Throwable {
            //初始化RunnerBuilder列表
            //该处将Junit所有的RunnerBuilder都创建好放入集合
            //从该处可以以知道该类为什么叫AllDefaultPossibilitiesBuilder了

    List<RunnerBuilder> builders= Arrays.asList(
            ignoredBuilder(),  //IgnoredBuilder需要忽略测试的RunnerBuilder
            annotatedBuilder(),  //AnnotatedBuilder带有注解的RunnerBuilder
            suiteMethodBuilder(),  //SuiteMethodBuilder
            junit3Builder(),  //JUnit3Builder(目测是为了兼容junit3)
            junit4Builder());  //JUnit4Builder

    for (RunnerBuilder each : builders) {
        Runner runner= each.safeRunnerForClass(testClass);
        if (runner != null)
            return runner;
    }
    return null;
}

让我们逐个看看各个builderrunnerForClass

  1. IgnoredBuilder:

     public Runner runnerForClass(Class<?> testClass) {
         if (testClass.getAnnotation(Ignore.class) != null)
             return new IgnoredClassRunner(testClass);
         }
         return null;
     }
    

可见如果测试类中加上了@Ignore则会使用该builder

  1. AnnotatedBuilder

     public Runner runnerForClass(Class<?> testClass) throws Exception {
         //获取测试类中用RunWith注解标注的类
         RunWith annotation= testClass.getAnnotation(RunWith.class);
         if (annotation != null)
             return buildRunner(annotation.value(), testClass);
         return null;
      }
    
     public Runner buildRunner(Class<? extends Runner> runnerClass,
         Class<?> testClass) throws Exception {
         try {
             ////创建RunWith注解中声明类的实例,并将测试类的class传入
             return runnerClass.getConstructor(Class.class).newInstance(
                 new Object[] { testClass });
         } catch (NoSuchMethodException e) {
             //先忽略异常处理
     }
    
  1. SuiteMethodBuilder
    进入suiteMethodBuilder()方法

     protected RunnerBuilder suiteMethodBuilder() {
         if (fCanUseSuiteMethod)
             return new SuiteMethodBuilder();
         return new NullBuilder();
     }
    

首先我们看到的是不是直接new SuiteMethodBuilder,而是首先看fCanUseSuiteMethod属性是否为true,还记得该属性是什么时候赋值的嘛?返回去看下Request.classes方法

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");
    }
}

正是new AllDefaultPossibilitiesBuilder(true); 中的true
也就是说,测试类中如果没有ignoredannotated,首先使用的RunnerBuilder实际是SuiteMethodBuilder,并执行该builderrunnerForClass方法,进入一探究竟

public Runner runnerForClass(Class<?> each) throws Throwable {
    //判断测试的class中是否有suite方法
    if (hasSuiteMethod(each))
        //创建suiteMethod,该类继承自JUnit38ClassRunner
        return new SuiteMethod(each);
    return null;
}

public boolean hasSuiteMethod(Class<?> testClass) {
    try {
        testClass.getMethod("suite");
    } catch (NoSuchMethodException e) {
        return false;
    }
    return true;
}
  1. JUnit3Builder:如果测试类使用的是Junit3的测试方式,则使用该builder,�该builder不再细看

  2. JUnit4Builder:该builder很简单,直接new BlockJUnit4ClassRunner

     public Runner runnerForClass(Class<?> testClass) throws Throwable {
         return new BlockJUnit4ClassRunner(testClass);
     }
    

让我们再回到我们的主线new Suite中,

public Suite(RunnerBuilder builder, Class<?>[] classes) throws InitializationError {
    this(null, builder.runners(null, classes));
}
protected Suite(Class<?> klass, List<Runner> runners) throws InitializationError {
    super(klass);
    //Collections.unmodifiableList将传入的List变得不可修改
    this.runners = Collections.unmodifiableList(runners);
}

总之,JunitCore中使用的Runner是直接newSuite,而这个Suite中属性List<Runner> runners,默认情况下,这些runner都是BlockJUnit4ClassRunner
至此Runner的构建完成,让我来接下来看下整个Runner构建的时序图

4.Runner构建时序图

Runner构建时序图
上一篇下一篇

猜你喜欢

热点阅读