TestNG框架源码走读二:测试套执行

TestNG框架源码走读一:入口

上一篇主要走读TestNG类的main函数入口,其中TestNG#runSuitesLocally()执行测试套的方法有3个核心逻辑需要详细走读下代码:
1.createSuiteRunners实现SuiteRunner的实例化。
2.runSuiteSequentially实现测试套的串行执行。
3.populateSuiteGraph/GraphThreadPoolExecutor实现测试套批量并行执行。

一、SuiteRunner实例化

在上一篇TestNG#runSuitesLocally()的源码中:


TestNG框架源码走读二:测试套执行_第1张图片

TestNG#createSuiteRunners()的源码如下:
核心逻辑是递归调用TestNG#createSuiteRunner()为每个测试套创建SuiteRunner实例:

  private void createSuiteRunners(SuiteRunnerMap suiteRunnerMap /* OUT */, XmlSuite xmlSuite) {
    // 根据命令行参数设置测试套的参数
    ......
    
    // 测试套下test的method-selector设置
    ......
    
    // createSuiteRunner(xmlSuite)为测试套创建执行器
    suiteRunnerMap.put(xmlSuite, createSuiteRunner(xmlSuite));
    
    // 递归为测试套下的子测试套创建执行器
    for (XmlSuite childSuite : xmlSuite.getChildSuites()) {
      createSuiteRunners(suiteRunnerMap, childSuite);
    }
  }

TestNG#createSuiteRunner()的源码如下:
1.调用SuiteRunner的构造器方法获得实例化对象result。
2.向result赋值测试套的一些监听器实例。
3.最终返回result对象,完成SuiteRunner对象的创建。

  private SuiteRunner createSuiteRunner(XmlSuite xmlSuite) {
    // SuiteRunner的实例化
    SuiteRunner result = new SuiteRunner(getConfiguration(), xmlSuite,
        m_outputDir,
        m_testRunnerFactory,
        m_useDefaultListeners,
        m_methodInterceptors,
        m_invokedMethodListeners.values(),
        m_testListeners.values(),
        m_classListeners.values());
    
    // 添加测试套的开始/结束事件监听器
    for (ISuiteListener isl : m_suiteListeners.values()) {
      result.addListener(isl);
    }

    // 添加报告生成的监听器,所有测试套执行结束时调用(Listener的调用代码在TestNG#run()中)
    for (IReporter r : result.getReporters()) {
      maybeAddListener(m_reporters, r.getClass(), r, true);
    }

    // 
    for (IConfigurationListener cl : m_configuration.getConfigurationListeners()) {
      result.addConfigurationListener(cl);
    }

    return result;
  }

上面就是SuiteRunner的实例化过程,具体SuiteRunner构造器方法中干了什么先略过,继续看看为测试套创建SuiteRunner实例后调用TestNG#runSuitesSequentially()如何实现测试套的执行。

二、调用SuiteRunner.run()执行测试套

1.走读TestNG#runSuitesSequentially()的源码,发现调用链如下:TestNG#runSuitesSequentially()->SuiteRunnerWorker#runSuite()->SuiteRunner#run(),横跨3个类后最终调用了SuiteRunner#run()

  // SuiteRunnerWorker#runSuite()源码
  private void runSuite(SuiteRunnerMap suiteRunnerMap, XmlSuite xmlSuite)
  {
    SuiteRunner suiteRunner = (SuiteRunner) suiteRunnerMap.get(xmlSuite);
    suiteRunner.run();
  }

2.SuiteRunner.run()如何实现执行测试套?
SuiteRunner#run()的源码如下,主要就是调用SuiteRunner#privateRun()以及前后监听器方法。

  @Override
  public void run() {
    invokeListeners(true /* start */);
    try {
      privateRun();
    }
    finally {
      invokeListeners(false /* stop */);
    }
  }

对照走读的代码注释,SuiteRunner#privateRun()的源码核心逻辑如下:

  • 1.从SuiteRunner.testRunners中获取测试套前置/后置方法
  • 2.调用测试套前置方法
  • 3.调用SuiteRunner#runSequentially()和SuiteRunner#runInParallelTestMode()执行所有testRunner(用例执行器)
  • 4.调用测试套后置方法。
    private void privateRun() {

    // Map for unicity, Linked for guaranteed order
    Map beforeSuiteMethods= new LinkedHashMap<>();
    Map afterSuiteMethods = new LinkedHashMap<>();

    IInvoker invoker = null;

    // 1.从testRunner集合中获取beforeSuite/afterSuite方法
    for (TestRunner tr: testRunners) {
      invoker = tr.getInvoker();
      
      for (ITestNGMethod m : tr.getBeforeSuiteMethods()) {
        beforeSuiteMethods.put(m.getConstructorOrMethod().getMethod(), m);
      }

      for (ITestNGMethod m : tr.getAfterSuiteMethods()) {
        afterSuiteMethods.put(m.getConstructorOrMethod().getMethod(), m);
      }
    }

    // 2.调用beforeSuite方法
    if (invoker != null) {
      if(! beforeSuiteMethods.values().isEmpty()) {
        invoker.invokeConfigurations(null,
            beforeSuiteMethods.values().toArray(new ITestNGMethod[beforeSuiteMethods.size()]),
            xmlSuite, xmlSuite.getParameters(), null, /* no parameter values */
            null /* instance */
        );
      }

      Utils.log("SuiteRunner", 3, "Created " + testRunners.size() + " TestRunners");

      // 3.执行所有的test runners
      boolean testsInParallel = XmlSuite.ParallelMode.TESTS.equals(xmlSuite.getParallel());
      if (!testsInParallel) {
        runSequentially();
      }
      else {
        runInParallelTestMode();
      }

      // 4.调用afterSuite方法
      if (! afterSuiteMethods.values().isEmpty()) {
        invoker.invokeConfigurations(null,
              afterSuiteMethods.values().toArray(new ITestNGMethod[afterSuiteMethods.size()]),
            xmlSuite, xmlSuite.getAllParameters(), null, /* no parameter values */

              null /* instance */);
      }
    }

如果进一步深入,需要了解:

  • SuiteRunner.testRunners是如何初始化的?
    beforeSuite/afterSuite方法取自testRunner的属性,那么testRunner的m_beforeSuiteMethods/m_afterSuiteMethods是如何赋值的?
  • SuiteRunner#runSequentially()和SuiteRunner#runInParallelTestMode()内部实现如何?

这些是接下来需要了解的TestRunner如何实现测试套下用例的执行。

你可能感兴趣的:(TestNG框架源码走读二:测试套执行)