Data-Driven Cross-Browser tests in Selenium Java Maven with TestNG
This tutorial integrates a data driven approach in the Selenium framework that was created by the tutorial for the page objects. The link to the git repository containing the source code of the page object tutorial can be found in the blog entry Use Page Objects in Selenium Java to keep the tests maintainable.
To perform several search tests in the current framework, multiple tests are necessary or the test needs to be extended by multiple searches. The data driven approach will add a new data provider that contains not only the browsers to execute but also a dataset stored in a CSV file. This way it is only necessary to add more test data to the CSV file to add a new test. With the data driven approach less code is needed to execute multiple tests and the maintainability of the code increases.
Table of contents
Create a CSV file to store the test data
Extend the browser provider with a browser class
Create a search result data provider
Implement the new provider in the test
Download source code
Next step
Extend the pom.xml
To read the CSV files the pom.xml needs to be extended by the dependency for opencsv. The dependency can be found in the maven repository and has to be added in the dependencies section of the pom.xml. In the end the pom.xml should contain the following information:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tws.testframework</groupId>
<artifactId>twstest</artifactId>
<version>1.0-SNAPSHOT</version>
<name>twstest</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>com.codeborne</groupId>
<artifactId>phantomjsdriver</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.30</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>5.3</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
Create a CSV file to store the test data
At first a new folder to contain all CSV files has to be created at src\test\java\com\tws\testframework\testdata. Within the folder create the file search.csv that will contain the test data for the execution. Every row will be one execution for the test and has to contain the following details:
- Search term
- Search result string
- Headline of the first search result
- Summary of the first search result
The CSV file will use a semicolon as separator, surround every entry with double quotes and should contain the following data:
"Cross-Browser Selenium Java with automated WebDriver Download";"Search Results for: Cross-Browser Selenium Java with automated WebDriver Download";"Cross-Browser Selenium Java with automated WebDriver Download";"Table of contents Install necessary dependenciesSet up a Maven Project from consoleConfigure the pom.xmlSet up a Browser class with automated"
"Use Page Objects in Selenium Java to keep the tests maintainable";"Search Results for: Use Page Objects in Selenium Java to keep the tests maintainable";"Use Page Objects in Selenium Java to keep the tests maintainable";"This tutorial will handle page objects in Selenium Java. It builds on the tutorial Cross-Browser Selenium Java with automated WebDriver"
Extend the browser provider with a browser class
To create a new data provides that reads the data from the CSV file it is first necessary to extend the browser class by a new method. This method will read the -Dbrowsers parameter from the maven call, add the values to an array and return it to the calling function. With the new function, the BrowserProvider.java file should contain the following code:
package com.tws.twsframework.dataprovider;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class BrowserProvider
{
@DataProvider (name = "browser-data-provider")
public Object[][] dpMethod(){
String givenBrowsers[] = System.getProperty("browsers").split(",");
Object browsers[][] = new Object[givenBrowsers.length][1];
for (int browserNo = 0; browserNo < givenBrowsers.length; browserNo++) {
browsers[browserNo][0] = givenBrowsers[browserNo];
}
return browsers;
}
public static String[] browser(){
String givenBrowsers[] = System.getProperty("browsers").split(",");
String browsers[] = new String[givenBrowsers.length];
for (int browserNo = 0; browserNo < givenBrowsers.length; browserNo++) {
browsers[browserNo] = givenBrowsers[browserNo];
}
return browsers;
}
}
Create a search result data provider
With the new function in place a data provider for the searches can be implemented. The file will be called SearchProvider.java and contain a data provider named search-data-provider. It will get the data from the new function in the BrowserProvider.java and read the data from the file search.csv to merge them in one data provider array. In the end the data provider array will contain a row for every entry in the CSV with a browser to execute. In this tutorial, the CSV file contains two data sets and by executing the tests for chrome, Firefox and opera the test will be executed 6 times. The source code of the SearchProvider will look like this:
package com.tws.twsframework.dataprovider;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import com.opencsv.*;
import com.opencsv.exceptions.CsvException;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public class SearchProvider
{
@DataProvider (name = "search-data-provider")
public Object[][] dpSearch(){
String [] browsers = BrowserProvider.browser();
String [][] fileData = null;
String [][] data;
FileReader filereader = null;
String pathToCSVFile = "src/test/java/com/tws/testframework/testdata/search.csv";
try{
filereader = new FileReader(pathToCSVFile);
}catch(Exception e){
System.out.println("File not found.");
}
CSVParser parser = new CSVParserBuilder().withSeparator(';').build();
try (CSVReader reader = new CSVReaderBuilder(filereader).withCSVParser(parser).build();) {
List<String[]> lines = reader.readAll();
fileData = lines.toArray(new String[lines.size()][]);
}catch(Exception e){
System.out.println("File not found.");
}
data = new String[fileData.length * browsers.length][fileData[0].length + 1];
int countResult = 0;
for(int countBrowser = 0; countBrowser < browsers.length; countBrowser++){
for (String[] csvRowData : fileData) {
int countEntry = 1;
for(String csvData : csvRowData){
data[countResult][countEntry] = csvData;
countEntry++;
}
data[countResult][0] = browsers[countBrowser];
countResult++;
}
}
return data;
}
}
Implement the new provider in the test
With the new data provider available the test can be changed to match the information from the data provider. Due to the fact that the summary of the first search result will be checked as well the page object for the search result page needs to be extended and should look like this:
package com.tws.twsframework.pageobjects;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.CacheLookup;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
public class SearchResult {
@FindBy(how = How.XPATH, using = "//*[@id='main']/header/h1")
@CacheLookup
public WebElement searchResultText;
@FindBy(how = How.XPATH, using = "//*[@id='post-wrapper']/article/div/header/h2/a")
@CacheLookup
public WebElement firstResultHeader;
@FindBy(how = How.XPATH, using = "//*[@id='post-wrapper']/article/div/div/p")
@CacheLookup
public WebElement firstResultSummary;
}
The parameters for the test need to be extended by a string variable for the search term, the search result term, the headline of the first test result and the summary of the first test result. Additionally, a check for the summary of the first search result needs to be added and the strings in the checks and the search have to be replaced by the variables. In the end the source code for the file FirstTest.java should look like this:
package com.tws.twsframework.tests;
import com.tws.twsframework.framework.Browser;
import com.tws.twsframework.dataprovider.SearchProvider;
import com.tws.twsframework.pageobjects.*;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.WebDriver;
import org.testng.Assert;
import org.testng.annotations.Test;
import org.testng.annotations.AfterMethod;
public class FirstTest{
public Browser browser;
public static String [][] fileData;
@Test(dataProvider = "search-data-provider", dataProviderClass = SearchProvider.class)
private void testCase(String browsername, String searchTerm, String searchResultString, String firstResultHeader, String firstResultSummary) throws Exception{
browser = new Browser(browsername, 10);
browser.driver.get("https://test-with-a-smile.de");
TwsMain poTwsMain = PageFactory.initElements(browser.driver, TwsMain.class);
Assert.assertEquals(true, poTwsMain.logo.isDisplayed());
poTwsMain.checkFooter();
poTwsMain.searchFor(searchTerm);
SearchResult poSearchResult = PageFactory.initElements(browser.driver, SearchResult.class);
Assert.assertEquals(searchResultString, poSearchResult.searchResultText.getText());
Assert.assertEquals(firstResultHeader, poSearchResult.firstResultHeader.getText());
Assert.assertEquals(firstResultSummary, poSearchResult.firstResultSummary.getText());
}
@AfterMethod
private void closeBrowsers(){
browser.driver.quit();
}
}
By executing the framework for the browsers Chrome, Opera and Firefox the result should look like this:
mvn test -Dbrowsers="chrome,opera,firefox"
[...]
[INFO] Tests run: 6, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 25.693 s - in com.tws.twsframework.tests.FirstTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 6, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 28.349 s
[INFO] Finished at: 2021-02-08T23:23:27+01:00
[INFO] ------------------------------------------------------------------------
Download source code
You can find the fully commented source code at GitHub:
https://github.com/TestautomationPopp/Data-Driven-Selenium-Tests
Next step
To improve this framework the next step is to implement a keyword driven approach or BDD with Gherkin-Notation.