Search code examples
javaselenium-webdrivertestngtestng-dataprovider

Running same tests against a large number of websites


I have a need to run the same tests against over 70 websites which are all functionally the same but have different skins. They are all accessed through different URLs however.

Using TestNG and Java, What would be an efficient way to pass the URLs to the tests so that I can: a) run each test against each site and report on same b) execute tests in parallel to save time (future need)

I want to store the URLs in a format such that it is exposed to end users and configurable by them. This would ideally be in a .csv or alternatively, as in the testng.xml file. I am thinking either @DataProvider or @Factory but am unsure how to use these in an efficient and maintainable way to take parameters from an external source or where in my current model such methods would be best placed? The difficulty I have is that I don't want to pass the data necessarily into @Test's, rather pass in one value at a time (a url) and run against all @Test annotated methods.

My current simple setup is as follows:

testngxml:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="Suite1" verbose="1">
<test name="FindARouteTest">
    <parameter name="number" value="1"/>
    <parameter name="from" value="LONDON"/>
    <parameter name="to" value="GLASGOW"/>
    <parameter name="emailAddress" value="[email protected]"/>
    <classes>
        <class name="acceptancetests.EndToEndTest">
        </class>
    </classes>
</test>

My acceptance test:

public class EndToEndTest extends DriverBase{

private HomePage home;
private String url;

@Factory(dataProvider = "urls", dataProviderClass = URLProvider.class)
public EndToEndTest(String url) {
    this.url = url;
}


@BeforeSuite
public void stuff(){
    newDriver();
}


@BeforeClass
public void setup(){
    home = new HomePage(driver, url);
}

@Test (priority = 1)
@Parameters({"from","to"})
public void searchForARoute(String from, String to) throws InterruptedException {
    home.selectWhereFrom(from);
    home.selectWhereTo(to);
    //some assertions...

My PageObject:

public class HomePage extends SeleniumBase {

public HomePage(WebDriver driver, String url) {
    super(driver, url);
    try {
        visit(url);
    } catch (MalformedURLException e) {
        e.printStackTrace();
    }
    driver.manage().window().maximize();
}

public void someMethodOrOther(){
//some methods...

My Selenium Methods BasePage:

public class SeleniumBase implements Config {

public WebDriver driver;
public String url;

public SeleniumBase(WebDriver driver) {
    this.driver = driver;
    this.url = url;
}

public void visit() throws MalformedURLException {
    driver.get(url);
} //more methods...

My Driver Base Page:

public class DriverBase implements Config {

public static WebDriver driver;
public static String url;

    protected void newDriver() {
        if (host.equals("localhost")) {
            if (browser.equals("firefox")) {
                System.setProperty("webdriver.gecko.driver",
                        System.getProperty("user.dir") + "\\drivers\\geckodriver.exe");
                FirefoxProfile fp = new FirefoxProfile();
//more stuff

URL Provider class:

public class URLProvider {

@DataProvider(name = "urls")
public static Object[][] dataProviderMethod()
{
    return new Object[][] {{"http://siteone.com"},
                            {"http://sitetwo.com"},
                            {"http://sitethree.com"}
    };
}
}

Finally, a Config which currently holds only a BaseUrl:

public interface Config {

String baseUrl = System.getProperty("baseUrl", 
String browser = System.getProperty("browser", "chrome");
String host = System.getProperty("host", "localhost");

}

Solution

  • You can use the @Factory annotation on the constructor for test class EndToEndTest and give it a dataprovider.

    private String url;
    
    @Factory(dataProvider = "urls", dataProviderClass = URLProvider.class)
    public EndToEndTest(String url) {
      this.url = url;
    }
    

    You need to provide the implementation of the URL data provider class to access the excel or whatever file you want and return an Object[][].

    Need to modify the constructors of HomePage and SeleniumBase to pass in the url which you are calling from your @BeforeClass method.

    This should create a separate instance for this test class for every url string and call the @Test methods.

    If you need to pass in more data than a string URL you can use an object instead. As I can see your passing 4 parameters in your testng.xml for a method.

    Parallelism should be pretty simple, guessing you would want to run all the @Test methods for a given url in a single thread. The parallel option would be "classes".