Search code examples
javaspringseleniumcucumbertestng

Cant run Cucumber tests in parallel using TestNG and SpringBootTest


I'm trying to run 2 Cucumber tests in parallel using TestNG and SpringBootTest but when my tests execute the following happens

  • 2 browsers open and both navigate to the Wikipedia homepage.
  • 1 browser continues the test, the other stays on the homepage
  • 1 test passes and the other fails

I'm not sure why one test stops executing, any help would be welcome.

Test Runner

@CucumberOptions(
        features = {
                "src/test/resources/feature/"
        },
        plugin = {
                "pretty",
                "html:target/cucumber/report-html",
                "json:target/cucumber/report.json",
                "junit:target/cucumber/junit_report.xml",
                "timeline:target/cucumber/timeline"
        })
public class ParallelRunner extends AbstractTestNGCucumberTests {

    @Override
    @DataProvider(parallel = true)
    public Object[][] scenarios() {
        return super.scenarios();
    }

}

DriverManager Class

@Component
public class DriverManager {

    private WebDriver webDriver;
    private Wait<WebDriver> webDriverWait;
    private static ThreadLocal<WebDriver> driverThreadLocal = new ThreadLocal<>();
    private static ThreadLocal<Wait<WebDriver>> driverWaitThreadLocal = new ThreadLocal<>();

    @Autowired
    private ApplicationProperties applicationProperties;

    public void driverManager() {
        if (getDriver() == null) {
            setLocalWebDriver();
        }
    }

    public void setLocalWebDriver() {
        switch (applicationProperties.getBrowser()) {
...
            case ("firefox"):
                System.setProperty("webdriver.gecko.driver", System.getProperty("user.dir") + "/src/test/resources/geckodriver");
                FirefoxOptions firefoxOptions = new FirefoxOptions();
//                firefoxOptions.setHeadless(true);
                firefoxOptions.setCapability("marionette", true);

                webDriver = new FirefoxDriver(firefoxOptions);
                break;
       ...
            default:
                throw new NoSuchElementException("Failed to create an instance of WebDriver for: " + applicationProperties.getBrowser());
        }
        driverThreadLocal.set(webDriver);
        webDriverWait = new WebDriverWait(webDriver, 10, 500);
        driverWaitThreadLocal.set(webDriverWait);
        try {
            Runtime.getRuntime().addShutdownHook(CLOSE_THREAD);
        }catch(Exception ex){
            System.out.println("ex.getMessage() = " + ex.getMessage());
        }
    }

    ...

Solution

  • Change the PageObject annotation and add @Scope("prototype") Refer

    @Retention(RUNTIME)
    @Target({ElementType.FIELD, ElementType.TYPE})
    @PageFactoryFinder(FindBy.FindByBuilder.class)
    @Lazy
    @Component
    @Scope("prototype")
    public @interface PageObject {
    }
    

    Now for each scenario you should get the new instance of page object .

    Also I may prefer to have some changes in DriverManager e.g.

    driverThreadLocal.set(new FirefoxDriver(firefoxOptions));
    driverWaitThreadLocal.set(new WebDriverWait(driverThreadLocal.get(), 10, 500));
    

    You can remove this logic of cleaning the drivers

    try { Runtime.getRuntime().addShutdownHook(CLOSE_THREAD); }catch(Exception ex){ System.out.println("ex.getMessage() = " + ex.getMessage()); }

    Move Driver.Quit to Hooks.java https://github.com/cmccarthyIrl/spring-cucumber-test-harness/blob/testng/wikipedia/src/test/java/com/cmccarthy/step/Hooks.java

      @After
        public void afterScenario(Scenario scenario) {
            hookUtil.endOfTest(StringUtils.capitalize(scenario.getStatus().toString()));
            driverManager.getDriver().quit();
        }