天天看點

TestNG源碼解讀(十)

繼上邊6.4 執行用例

上一篇講到了runSuitesSequentially這個方法會去調用SuiteRunnerWorker.run方法,那麼run方法的具體實作又是什麼樣的呢?

走讀本段代碼後發現run方法中又繼續調用了runSuite方法,該方法主要作用:執行suite然後将結果存到suiteRunnerMap中。執行suite的方法則是調用suiteRunner.run()方法,繼續細看suiteRunner.run()方法

SuiteRunnerWorker srw = new SuiteRunnerWorker(suiteRunnerMap.get(xmlSuite), suiteRunnerMap,
      verbose, defaultSuiteName);
srw.run();

  @Override
  public void run() {
    runSuite(m_suiteRunnerMap, m_suiteRunner.getXmlSuite());
  }


   /**
   * Runs a suite
   * @param suiteRunnerMap map of suiteRunners that are updated with test results
   * @param xmlSuite XML suites to run
   */
  private void runSuite(SuiteRunnerMap suiteRunnerMap /* OUT */, XmlSuite xmlSuite)
  {
    //日志級别大于0時,在控制台中輸出要執行的tetsng.xml的路徑,如下圖一
    if (m_verbose > 0) {
      StringBuffer allFiles = new StringBuffer();
      allFiles.append("  ").append(xmlSuite.getFileName() != null
          ? xmlSuite.getFileName() : m_defaultSuiteName).append('\n');
      Utils.log("TestNG", 0, "Running:\n" + allFiles.toString());
    }

    SuiteRunner suiteRunner = (SuiteRunner) suiteRunnerMap.get(xmlSuite);
    suiteRunner.run();

  
    //
    // Display the final statistics
    // 顯示最終的統計,輸出總個數,失敗的個數,skip的個數,如圖二
    //
    if (xmlSuite.getVerbose() > 0) {
      SuiteResultCounts counts = new SuiteResultCounts();
      synchronized (suiteRunnerMap) {
        counts.calculateResultCounts(xmlSuite, suiteRunnerMap);
      }

      StringBuffer bufLog = new StringBuffer("\n===============================================\n")
          .append(xmlSuite.getName());
      bufLog.append("\nTotal tests run: ")
          .append(counts.m_total).append(", Failures: ").append(counts.m_failed)
          .append(", Skips: ").append(counts.m_skipped);
      if(counts.m_confFailures > 0 || counts.m_confSkips > 0) {
        bufLog.append("\nConfiguration Failures: ").append(counts.m_confFailures)
             .append(", Skips: ").append(counts.m_confSkips);
      }
      bufLog.append("\n===============================================\n");
      System.out.println(bufLog.toString());
    }
  }
           
TestNG源碼解讀(十)

圖一​​​

TestNG源碼解讀(十)

圖二

suiteRunner.run()方法又調用了同類中的privateRun()方法,該方法主要作用是先執行beforeSuiteMethods方法然後執行所有test最後在執行afterSuiteMethods,其核心還是執行所有test的runSequentially()方法,runSequentially()方法又繼續調用runTest方法,而runTest方法就是執行每一個<test>用例然後将執行結果put到m_suiteResults中

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




  private void privateRun() {

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

    IInvoker invoker = null;

    // Get the invoker and find all the suite level methods
    for (TestRunner tr: m_testRunners) {
      // TODO: Code smell.  Invoker should belong to SuiteRunner, not TestRunner
      // -- cbeust
      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);
      }
    }

    //
    // Invoke beforeSuite methods (the invoker can be null
    // if the suite we are currently running only contains
    // a <file-suite> tag and no real tests)
    //
    if (invoker != null) {
      if(beforeSuiteMethods.values().size() > 0) {
        invoker.invokeConfigurations(null,
            beforeSuiteMethods.values().toArray(new ITestNGMethod[beforeSuiteMethods.size()]),
            m_suite, m_suite.getParameters(), null, /* no parameter values */
            null /* instance */
        );
      }

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

      //
      // Run all the test runners
      //
      boolean testsInParallel = XmlSuite.ParallelMode.TESTS.equals(m_suite.getParallel());
      if (!testsInParallel) {
        runSequentially();
      }
      else {
        runInParallelTestMode();
      }

      //
      // Invoke afterSuite methods
      //
      if (afterSuiteMethods.values().size() > 0) {
        invoker.invokeConfigurations(null,
              afterSuiteMethods.values().toArray(new ITestNGMethod[afterSuiteMethods.size()]),
              m_suite, m_suite.getAllParameters(), null, /* no parameter values */

              null /* instance */);
      }
    }
  }



  private void runSequentially() {
    for (TestRunner tr : m_testRunners) {
      runTest(tr);
    }
  }

  private void runTest(TestRunner tr) {
    tr.run();

    ISuiteResult sr = new SuiteResult(m_suite, tr);
    m_suiteResults.put(tr.getName(), sr);
  }