简体   繁体   中英

how to run my selenium test methods in parallel using testng

I am trying to run my automated tests(Selenium webdriver) in parallel using testng. this is the node which I am running:

java -Dwebdriver.gecko.driver=chromedriver.exe -jar selenium-server-standalone-3.4.0.jar -role node -hub http://localhost:4444/grid/register -browser browserName=chrome,maxInstances=2 -maxSession 2

this is my test class:

public class TestParallel {

Login login;

//@BeforeMethod(alwaysRun = true)
public SeleniumDriverCore testSetup() throws FileNotFoundException, IOException{
    SeleniumDriverCore driver = new SeleniumDriverCore("config/chromeDriverConfig");
    Properties config = new Properties();
    config.load(new FileInputStream("config/testConfig"));
    this.login = new Login(driver);
    driver.browser.open("https://test.test.xyz");

    driver.browser.maximize();
    driver.waits.waitForPageToLoad();
    return driver;
}

@Test(groups={"parallel"})
public void test_one() throws FileNotFoundException, IOException{
    SeleniumDriverCore driver=testSetup();
    login.navigateToPage(Pages.LOGIN);
    login.assertion.verifyLoginPopupAndTitleDisplayed();
    testCleanup(driver);
}

@Test(groups={"parallel"})
public void test_two() throws FileNotFoundException, IOException{
    SeleniumDriverCore driver=testSetup();
    login.navigateToPage(Pages.LOGIN);
    login.assertion.verifyLoginPopupAndTitleDisplayed();
    testCleanup(driver);
}

@Test(groups={"parallel"})
public void test_three() throws FileNotFoundException, IOException{
    SeleniumDriverCore driver=testSetup();
    login.navigateToPage(Pages.LOGIN);
    login.assertion.verifyLoginPopupAndTitleDisplayed();
    testCleanup(driver);
}

@Test(groups={"parallel"})
public void test_four() throws FileNotFoundException, IOException{
    SeleniumDriverCore driver=testSetup();
    login.navigateToPage(Pages.LOGIN);
    login.assertion.verifyLoginPopupAndTitleDisplayed();
    testCleanup(driver);
}


public void testCleanup(SeleniumDriverCore driver){
    driver.close();
    driver.quit();
}

}

and here is my xml:

<suite name="Ontega - All Tests Mobile" parallel="methods" thread-count="2">
    <test name="Ontega - All Tests Mobile">
        <groups>
            <run>
                <include name="parallel"/>
                <exclude name="open-defects"/>
            </run>
        </groups>
        <packages>
            <package name="tests.*"/>
        </packages>
    </test>
</suite>

when I run the XML, I expect to have my tests to be running on two browsers in two threads at a time, however when I run the XML I get two browser instances running at the first time and then they are incremented and 50% of the tests are failing, as you can see I am trying to instantiate the driver in each of my methods, although it's not how my framework is working, but I am trying to get to the bottleneck of this issue. Any help would be very appreciated Thanks in advance

Here are some ways of doing this in TestNG. You basically manage your webdriver instantiation and cleanup via a @BeforeMethod and a @AfterMethod config methods. So then you would need to decide how would you want to share the created webdriver instance with your @Test method. For that you have three options:

  1. You make use of a ThreadLocal variant, because TestNG guarantees to you that it will execute @BeforeMethod , @Test and @AfterMethod all in the same thread.

Here's a sample that shows you this in action

import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.ITestResult;
import org.testng.Reporter;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class TestClassSampleUsingThreadLocal {
    private static final ThreadLocal<RemoteWebDriver> drivers = new ThreadLocal<>();

    @BeforeMethod
    public void instantiateBrowser(ITestResult testResult) {
        RemoteWebDriver driver = new ChromeDriver();
        drivers.set(driver);
    }

    @Test(dataProvider = "dp")
    public void testMethod(String url) {
        Reporter.log("Launching the URL [" + url + "] on Thread [" + Thread.currentThread().getId() + "]", true);
        driver().get(url);
        Reporter.log("Page Title :" + driver().getTitle(), true);
    }

    @DataProvider(name = "dp", parallel = true)
    public Object[][] getData() {
        return new Object[][]{
                {"http://www.google.com"}, {"http://www.stackoverflow.com"}, {"http://facebook.com"}
        };
    }

    @AfterMethod
    public void cleanupBrowser() {
        RemoteWebDriver driver = driver();
        driver.quit();
    }

    private RemoteWebDriver driver() {
        RemoteWebDriver driver = drivers.get();
        if (driver == null) {
            throw new IllegalStateException("Driver should have not been null.");
        }
        return driver;
    }

}
  1. You can share the webdriver instance via the ITestResult object. Here's a sample that shows that in action.
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.ITestResult;
import org.testng.Reporter;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class TestClassSample {
    private static final String WEBDRIVER = "driver";

    @BeforeMethod
    public void instantiateBrowser(ITestResult testResult) {
        RemoteWebDriver driver = new ChromeDriver();
        testResult.setAttribute(WEBDRIVER, driver);
    }

    @Test(dataProvider = "dp")
    public void testMethod(String url) {
        Reporter.log("Launching the URL [" + url + "] on Thread [" + Thread.currentThread().getId() + "]", true);
        driver().get(url);
        Reporter.log("Page Title :" + driver().getTitle(), true);
    }

    @DataProvider(name = "dp", parallel = true)
    public Object[][] getData() {
        return new Object[][]{
                {"http://www.google.com"},
                {"http://www.stackoverflow.com"},
                {"http://facebook.com"}
        };
    }

    @AfterMethod
    public void cleanupBrowser(ITestResult testResult) {
        RemoteWebDriver driver = driver(testResult);
        driver.quit();
    }

    private RemoteWebDriver driver() {
        return driver(Reporter.getCurrentTestResult());
    }

    private RemoteWebDriver driver(ITestResult testResult) {
        if (testResult == null) {
            throw new IllegalStateException("testResult should have not been null.");
        }
        Object driverObject = testResult.getAttribute(WEBDRIVER);
        if (driverObject == null) {
            throw new IllegalStateException("Driver should have not been null.");
        }
        if (!(driverObject instanceof RemoteWebDriver)) {
            throw new IllegalStateException("Driver is not a valid webdriver object");
        }
        return (RemoteWebDriver) driverObject;
    }
}
  1. You extract out the webdriver instantiation and cleanup into a TestNG listener (one that implements a org.testng.IInvokedMethodListener which sets the created webdriver into the ITestResult (as shown in option 2) or into a ThreadLocal (as shown in option 1). You can find more details about this option along with code snippets in my blog post .

It seems you creating multiple driver per test. I guess you need to keep some part of code outside testSetup() method

SeleniumDriverCore driver = new SeleniumDriverCore("config/chromeDriverConfig");
Properties config = new Properties();
config.load(new FileInputStream("config/testConfig"))

I am sharing part of my code which I am using for parallel testing, may be that will help in your case 在此处输入图片说明

My xml 在此处输入图片说明

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