简体   繁体   中英

Screenshot on failed tests using Junit 5 Selenium parallel execution

I would like to take a screenshot every single time test fails or if multiple tests then multiple screenshots of course.

So far I understand that I can just wrap my single test with a try catch block and proceed taking a screenshot, however I would not want to wrap it in every test I have. I want it to apply to all of them without wrapping each one, do I have to do that in my setup?

public class WebDriverSettings
{

    protected WebDriver driver;
    protected String TARGET_URL;

    @BeforeEach
    public void setUp()
    {
        WebDriverManager.chromedriver().setup();
        driver = new ChromeDriver(new ChromeOptions().addArguments("window-size=1920x1480"));
        driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
        loginToEnvironment();
    }
}

public class LoginServiceTest extends WebDriverSettings
{
    private LoginModal loginModal;
    private AccountApi accountApi;
    private Credentials credentials;

    @BeforeEach
    public void setUp()
    {
        super.setUp();
        credentials = new SignUp();
        accountApi = new AccountApi(credentials);
        accountApi.createAccount();
        loginModal = new HomePage(driver).acceptCookies().clickOnMyAccountTab().switchToLoginTab();
    }

    @Test
    public void shouldSuccessfullyLogin()
    {
        try
        {
            accountApi.createAccount();
            assertFalse(loginModal.login(credentials).getMyAccountName().getText().isEmpty());
        } catch (Exception e)
        {
            try
            {
                File screenshotFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
                FileUtils.copyFile(screenshotFile, new File("path"));
            } catch (IOException ioException)
            {
                ioException.printStackTrace();
            }
            accountApi.closeAccount();
        }
    }
}

Solution advised by Jeff

So creating Util package and adding a class that would be responsible for creating a screenshot also it would generate random name but needs to be refactored i just made it quickly to make it work

public class ScreenShotCreator {

    public static void takeScreenShot(WebDriver driver) {
        try {
            File screenshotFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
            FileUtils.copyFile(screenshotFile, new File(fileNameGenerator()));
        } catch (IOException e) {
            throw new RuntimeException("Could not make a screenshot");
        }
    }

    // creating this for test purposes , need to use string builder instead to append it instead of adding it
    private static String fileNameGenerator() {
        SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy-HH:mm");
        String path = ".....";
        return path + "screenshot" + formatter.format(new Date()) + " " + RandomStringUtils.randomAlphanumeric(10) + ".png";
    }

Then before closing it down just call the created method

@AfterEach
    public void tearDown() {
        ScreenShotCreator.takeScreenShot(driver);
        driver.manage().deleteAllCookies();
        driver.close();
        driver.quit();
    }

What I would suggest is

  1. Create a method to take a screenshot and put that in a Utils class and call it when you want to take a screenshot. This will make taking a screenshot a lot easier because all the code lives in one place and can be easily called from anywhere.

  2. Create a tearDown() method, if you don't have one already. Looks like it would go in the WebDriverSettings class from your currently posted code. Mark it with an @AfterEach annotation and then detect a failed test case and if it failed, take a screenshot.

    If you aren't sure how to do that, there's a class in JUnit 4.9 and later called TestWatcher that you can use. There are lots of examples on the web on how to use it.

The solution that worked for me was to create this extension:

package some.thing;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;

public class Screenshotter implements AfterTestExecutionCallback {
    private static final Logger LOG = LogManager.getLogger();
    private static WebDriver driver;

    public static void setDriver(WebDriver driver) {
        Screenshotter.driver = driver;
    }

    @Override
    public void afterTestExecution(ExtensionContext context) throws Exception {
        if (context.getExecutionException().isPresent()) { // if the test execution has failed
            String baseFileName = context.getRequiredTestClass().getSimpleName() + "-"
                    + context.getRequiredTestMethod().getName()
                    + LocalDateTime.now().format(DateTimeFormatter.ofPattern("-yyMMdd-HHmmss"));
            File targetFile = new File("somewhere/" + baseFileName + ".png");
            File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
            Files.copy(scrFile.toPath(), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
            targetFile.setReadable(true, false);
            LOG.info("Screenshot saved to " + targetFile.toPath());
        }
    }
}

Then apply it to the relevant test class like so:

@ExtendWith(Screenshotter.class)
public class SomeTest {
    ...
    @BeforeAll
    public void initialize() {
        ...
        Screenshotter.setDriver(driver);
        ...
    }
    ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM