首页 > 解决方案 > TestNG Listener onFinish(ITestContext context) 无法获取 ThreadLocal 实例(它返回 null)但 onTestFailure(ITestResult result) 工作正常

问题描述

我在这里发现了一个类似的问题,但不一样。

我使用 Selenium 和 TestNG 创建测试。

我实现了 TestNG Listerner,所以在测试失败和测试完成的情况下,我都可以获取 Chrome 浏览器日志。

当我实例化 Chrome 驱动程序时,我将它包装在一个 ThreadLocal 中,以便在我想使用实例时可以使用 getter 和 setter。

TestNg 监听器看起来像这样

public class MyListeners extends TestBase implements ITestListener, ISuiteListener {

  @Override
  public void onStart(ISuite suite) {

  }

  @Override
  public void onFinish(ISuite suite) {

  }

  @Override
  public void onTestStart(ITestResult result) {

  }

  @Override
  public void onTestSuccess(ITestResult result) {

  }

  @Override
  public void onTestFailure(ITestResult result) {

    //I set the attribute "browser" in @Test with value "chrome" so this following block will be run
    if (result.getAttribute("browser").equals("chrome")) {
      super.grablog(); //Works perfectly fine
    }

  }

  @Override
  public void onTestSkipped(ITestResult result) {

  }

  @Override
  public void onTestFailedButWithinSuccessPercentage(ITestResult result) {

  }

  @Override
  public void onStart(ITestContext context) {

  }

  @Override
  public void onFinish(ITestContext context) {

    int numberOfFailedTest = context.getFailedTests().size();

    if (numberOfFailedTest == 0) {
      //No Test Fails

      //Just a method to know which browser is used
      String usedBrowser = null;
      Set < ITestResult > passedTest = context.getPassedTests().getAllResults();
      Iterator < ITestResult > i = passedTest.iterator();
      if (i.hasNext()) {
        usedBrowser = i.next().getAttribute("browser").toString();
      }

      //I set the attribute "browser" in @Test with value "chrome" so this following block will be run
      if (usedBrowser.equals("chrome")) {
        super.grablog(); // Will not work
      }

    }
  }
}

这个 Listener 类有超类 TestBase,看起来像这样

public class TestBase {

  public void initiate(String browser, String URL) throws InterruptedException {

    //Initiating Chrome Driver , usual standard procedur
    if (browser.equals("chrome")) {
      System.setProperty("webdriver.chrome.driver", System.getProperty("user.dir") + "\\src\\test\\resources\\executeable\\chromedriver.exe");
      DesiredCapabilities caps = DesiredCapabilities.chrome();
      LoggingPreferences logPrefs = new LoggingPreferences();
      logPrefs.enable(LogType.BROWSER, Level.ALL);
      caps.setCapability(CapabilityType.LOGGING_PREFS, logPrefs);

      ChromeOptions options = new ChromeOptions();
      options.addArguments("start-maximized");

      options.merge(caps);
      driver = new ChromeDriver(options);
    }

    //Wrap the initiated driver to our local Thread
    DriverManager.setDriverThread(this.driver);
    DriverManager.getDriverThread().manage().window().maximize();
    DriverManager.getDriverThread().get(URL);
  }

  public void grablog() {
    Grablog grablog = new Grablog();
    grablog.grabbing();
  }

}

管理驱动线程的 Driver 类

public class DriverManager {

  private static ThreadLocal < WebDriver > driverThread = new ThreadLocal < > ();

  public static WebDriver getDriverThread() {
    return driverThread.get();
  }

  public static void setDriverThread(WebDriver driver) {
    driverThread.set(driver);
  }
}

在我的@Test课堂上,我调用initiate()来启动 Chrome 浏览器initiate("chrome", "www.website.com");(否则,浏览器将无法启动)。

令人困惑的部分在这里。

public class Grablog {

  //When TestNG Listener onFinish invoke this grabbing() , then new DriverManager().getDriverThread() will return null (bad)
  //When TestNG Listener onTestFailure invoke this grabbing() , then new DriverManager().getDriverThread() will return a driver instance (good)
  public void grabbing() {

    LogEntries logEntries = new DriverManager().getDriverThread().manage().logs().get(LogType.BROWSER);

    //
    //Some codes here to save the log to a txt file
    //

  }
}

new DriverManager().getDriverThread()将在调用侦听器时返回驱动程序实例OnTestFailure()(完美,正是我想要的),但在调用null侦听器时将返回OnFinish()(不是我想要的)。我不杀死驱动程序实例(不使用quit()也不close()使用方法)。

全部成功完成后,将调用@Test监听器,不抛出异常。OnFinish()没有抛出错误信息。测试将以绿色勾号结束。全是绿色的。但我没有得到我的日志文件。经过一些故障排除并在调试模式下运行,我发现根本原因是驱动程序实例为空。为什么为空?

我想知道,为什么这两种 Listener 方法的工作方式不同?我怀疑,当OnFinish()被调用时,所有测试都已完成,因此所有实例都会被垃圾收集器自动销毁?这可能是原因吗?

我试着把它放进去super.grablog()public void onTestSuccess(ITestResult result)它也很好用。只是OnFinish()工作方式不同。

是否有针对此特定问题的解决方法?或者我可能会做错什么?
在其他帖子中,有人建议在 TestNG Listener 中初始化驱动程序。我稍后可能会尝试,但我更喜欢在我自己的课堂上(而不是在 Listener 中)这样做。谢谢。

1 月 7 日更新:

我用一种方法创建了一个新类,@AfterSuite并将代码块Listener OnFinish()@AfterSuite. 我在 testng.xml 中列出了新类,因此它将被执行。

我遇到了同样的问题,但这次java.lang.NullPointerException是由于相同的原因导致的完全相同的行(new DriverManager().getDriverThread()返回 null)。

标签: javaseleniumtestng

解决方案


推荐阅读