Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selenium testing on different browsers using TestNG

So currently I am doing something like this to do cross browser testing:

@DataProvider(name="foo")
public Object[][] getDrivers() {
    DesiredCapabilities firefoxCapabs = DesiredCapabilities.firefox();
    capabillities.setCapability("version", "26");
    capabillities.setCapability("platform", Platform.WINDOWS);
    DesiredCapabilities chromeCapabs = ....
    ....
    DesiredCapabilities ieCapabs = ...
    ....

    return new Object[][]{
        {new RemoteWebDriver(url, firefoxCapabs)}, 
        {new RemoteWebDriver(url, chromeCapabs)},
        ......
    };
}

@Test(dataProvider="foo")
public void testSomething(WebDriver driver) {
    //some test
}

This seems extremely inefficient as I am basically creating and destroying these WebDriver objects every time I run a test. Is there no way to do something like this at least at the TestSuite level so that I am not generating and destroying these objects for every test. I would like something like below. I am aware that you cannot have a DataProvider for @BeforeSuite methods!

public class TestSuite{
    public static WebDriver driver;
    @BeforeSuite(dataProvider="foo")
    public void setDriver(WebDriver driver) {
         this.driver = driver;
    }
}

public class TestClass {
    private WebDriver driver;

    @BeforeTest
    public void getDriver() {
        this.driver = TestSuite.driver;
    }    

    @Test
    public void myTest() {
        //use this.driver to do testing stuff
    }
}

Are there options I am not seeing to do something like this?

like image 895
thatidiotguy Avatar asked Jan 24 '14 15:01

thatidiotguy


3 Answers

Sauce Labs On Demand has a great plugin for Jenkins (https://saucelabs.com/jenkins/5). Their approach is pretty simple: you check/uncheck what OSs and browsers you to test and Jenkins sets environment variables for your tests to pick up. Below is a complete example of using Spring's @Configuration:

package com.acme.test;

import java.net.MalformedURLException;
import java.net.URL;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.core.env.Environment;

@Configuration
public class SauceLabsWebDriverConfiguration {

    @Autowired private Environment environment;

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public WebDriver webDriver() throws MalformedURLException {
        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability("version", environment.getProperty("SELENIUM_VERSION", "17.0.1"));
        capabilities.setCapability("platform", environment.getProperty("SELENIUM_PLATFORM", "XP"));
        capabilities.setCapability("browserName", environment.getProperty("SELENIUM_BROWSER", "firefox"));
        String username = environment.getProperty("SAUCE_USER_NAME", "enter_your_username_here");
        String accessKey = environment.getProperty("SAUCE_API_KEY", "enter_your_api_here");
        return new RemoteWebDriver(new URL("http://" + username + ":" + accessKey + "@ondemand.saucelabs.com:80/wd/hub"), capabilities);
    }
}

Sauce Labs has some free plans, but if you don't want to use them, you should be able to switch out the last part that constructs the URL ("http://" + username + ":" + accessKey + "@ondemand.saucelabs.com:80/wd/hub") the actual server URL you want to point to ("http://mydomain.com").

The trick is basically to replace hard-coded browser/capability names with environment provided ones and then have your build runner (ant/maven/etc) set environment variables for each of the OS/browser combos you want to test and "loop" over those somehow. SauceLabs plugins just makes it easy to do the looping. You can still provide default fallback values in case you want to run a simple local test.

// Before
DesiredCapabilities firefoxCapabs = DesiredCapabilities.firefox();
capabillities.setCapability("version", "26");
capabillities.setCapability("platform", Platform.WINDOWS);

// After 
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("version", environment.getProperty("SELENIUM_VERSION", "17.0.1"));
capabilities.setCapability("platform", environment.getProperty("SELENIUM_PLATFORM", "XP"));
capabilities.setCapability("browserName", environment.getProperty("SELENIUM_BROWSER", "firefox"));

Hope it helps.

like image 122
SergeyB Avatar answered Oct 13 '22 04:10

SergeyB


Two ways to implement this

1) Since you are using a Suite, you can create two tests that will run at the start of the suite and the end , one will setup Webdriver and store it in a global value; which each test class can later access , and the second will close the webdriver.

2) You can use dependency injection to setup webdriver as a singleton/global value and inject it to each test http://testng.org/doc/documentation-main.html#dependency-injection

like image 33
ShayM Avatar answered Oct 13 '22 05:10

ShayM


Here's something you can try: Use the ITestListener. Implement the onStart and onFinish methods to create threadlocal variables for your driver based on the param value i.e. In onStart(context), fetch your parameter value using

context.getCurrentXmlTest().getParameter("something")

Depending on the param value populate the threadlocal value with appropriate initialized driver

ThreadLocal<WebDriver> threadDriver = new ThreadLocal<WebDriver>()

In your xml pass the browser as parameter for individual test tags and set parallel=tests

<test name="1" >
    <parameter name="browser" value="ff"></parameter>
        <classes>
            <class name="com.nv.test.testngtests.Eq"/>
        </classes>
    </test>
     <test name="2" >
    <parameter name="browser" value="chrome"></parameter>
        <classes>
            <class name="com.nv.test.testngtests.Eq"/>
        </classes>
    </test>

You can take it at suite level too with ISuiteListener, but I think with the test approach you atleast get a chance to have some kind of parallelism

like image 1
niharika_neo Avatar answered Oct 13 '22 04:10

niharika_neo