1

I'm working on automating some tests at work and want to add the ability to take a screenshot in case of a failed test. I know this can easily be done in a clean way with TestNG but all of our unit/integration tests are using jUnit so I'll have to stick to that.

I have the logic/code for it almost ready and it's working but I'm running into a conflict because the @Rule is executed after the @After tearDown() method and by that time the webDriver doesn't exist anymore so it doesn't have anything to take the screenshot from.

Here's my code:

  @Rule
  public TestRule testWatcher = new TestWatcher() {
    @Override
    protected void failed(Throwable e, Description description) {
      File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
      String scrFilename = "Screenshot_"+ DateUtils.now().getTime()+".png";
      File outputFile = new File(screenshotPath, scrFilename);
      try {
        LOGGER.info("Saving screenshot of failed test...");
        FileUtils.copyFile(scrFile, outputFile);
      } catch (IOException ioe) {
        LOGGER.warn("Error taking screenshot");
      }
    }
  };

And this is the tearDown method:

  @After
  public void tearDown() {
    LOGGER.info("Quitting browser");
    driver.quit();

    LOGGER.info("Stopping Chrome Driver Service");
    chromeDriverService.stop();
  }

The error I'm getting as it is now is this:

org.openqa.selenium.remote.SessionNotFoundException: Session ID is null. Using WebDriver after calling quit()?

Which is of course what's happening. It's trying to call the code to take a screenshot after calling driver.quit() and chromeDriverService.stop(). If I comment those 2 lines then the screenshot is correctly saved.

What would be the proper way to handle this? Is there any way I can set it so the @Rule runs first then the @After?

Laucien
  • 511
  • 2
  • 5
  • 17

1 Answers1

0

Okay, browsing/searching around a bit more I found this question here which answers exactly what I wanted. What I did was add the tearDown code into the @Rule then call it with a finally after the try/catch block.

  @Rule
  public TestRule testWatcher = new TestWatcher() {
    @Override
    protected void failed(Throwable e, Description description) {
      File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
      String scrFilename = "Screenshot_"+ DateUtils.now().getTime()+".png";
      File outputFile = new File(screenshotPath, scrFilename);
      try {
        LOGGER.info("Saving screenshot of failed test...");
        FileUtils.copyFile(scrFile, outputFile);
      } catch (IOException ioe) {
        LOGGER.warn("Error taking screenshot");
      } finally {
        tearDown();
      }
    }

    public void tearDown() {
      LOGGER.info("Quitting browser");
      driver.quit();

      LOGGER.info("Stopping Chrome Driver Service");
      chromeDriverService.stop();
    }
  };
Community
  • 1
  • 1
Laucien
  • 511
  • 2
  • 5
  • 17