In this 2nd TestNG article, we will dive into Data Driven Testing. Data Driven Testing is when data is stored in a data source and then used as input for a Test Method. As automation engineers, we have the ability to store many data sets in a data source. Therefore, one Test Script will execute multiple times utilizing different data.
The data source can be an xml file, properties file, excel spreadsheet, etc. Within the data source, our data sets can be the same type of data or a mixture of data. By the end of this article, you will know why Data Driven Testing is important and how to drive data to your test using TestNG’s:
- DataProvider Annotation
- dataProvider Attribute
- dataProviderClass Attribute
- xml File “i.e., Cross Browser Testing”
Note: Code from this article is located on GitHub https://github.com/RexJonesII/TestProject-TestNG
Tutorial Chapters
- The Power of Test Next Generation (Chapter 1)
- You’re here → Data Driven Testing (Chapter 2)
- Dependency Testing (Chapter 3)
Why Data Driven Testing Is Important?
Data Driven Testing is important because it saves time and separates logic from data. Time is saved when we create one Test Method and not multiple Test Methods. The Test Method’s logic is separated from each data set allowing us to execute different data combinations for the same test. Therefore, we leverage one Test Method and multiple data sets. Here’s a Data Driven Testing process flow:
Data Providers
TestNG supports two ways for passing parameters directly to our Test Methods. We can pass parameters through Data Providers or an xml File. This section focuses on Data Providers which contain a DataProvider Annotation, dataProvider Attribute, and dataProviderClass Attribute. Here’s a couple of screenshots displaying each Data Provider via TestNG’s annotations package:
DataProvider Annotation
The DataProvider Annotation can supply hardcoded data or retrieve data from a source. Some of the data sources are excel spreadsheet, database, properties file, network, and text file (i.e., csv.). In this tutorial, we are going to supply hardcoded data with each data set presenting two purposes at the same time.
- Pass an unlimited number of values to the Test Method
- Allow the Test Method to be invoked with different data sets
The values can be any Java Data Type such as int, boolean, and String. All of the data sets will execute and have its own Test Result. The following code snippets show a DataProvider Annotation with a String Data Type:
@DataProvider public Object [] [] logInData () { Object [] [] data = new Object [3] [2]; data [0] [0] = "[email protected]"; data [0] [1] = "Password_ABC"; data [1] [0] = "[email protected]"; data [1] [1] = "UseMyValidPassword"; data [2] [0] = "[email protected]"; data [2] [1] = "InvalidPassword"; return data; }
@DataProvider (name = "provideLogInData") public Object [] [] logInData () { Object [] [] data = new Object [3] [2]; data [0] [0] = "[email protected]"; data [0] [1] = "Password_ABC"; data [1] [0] = "[email protected]"; data [1] [1] = "UseMyValidPassword"; data [2] [0] = "[email protected]"; data [2] [1] = "InvalidPassword"; return data; }
Notice, the DataProvider’s name is optional. The first code snippet does not contain a name attribute. However, the second code snippet encloses provideLogInData as the name. Either way is okay. If we do not specify the name then the method’s name “logInData” is automatically used as the default name.
Anyone of the DataProvider’s name (provideLogInData or logInData) will be referenced in the @Test Annotation. Although both names are valid, it’s safe to use the name attribute and not rely on the default method name. The default method name can change and cause our test to fail.
Both snippets declare the method with an Object [] [] Data Type named logInData. The next line initializes a Two-Dimensional array called data with 3 rows and 2 columns. Afterwards, three hardcoded data sets contain a username and password to log into TestProject. The usernames are located in the first column and passwords in the second column:
- Usernames
- data [0] data [0]
- data [1] data [0]
- data [2] data [0]
- Passwords
- data [0] data [1]
- data [1] data [1]
- data [2] data [1]
The first and third log in data sets are invalid while the second data set is valid. Sign up for free and get your valid log in credentials. Click Here. The last line in each code snippet returns data so the Test Method can attempt to log into TestProject.
dataProvider Attribute
The dataProvider Attribute maps the DataProvider Annotation to the Test Method. Attributes begin with a lowercase letter “dataProvider” and Annotations begin an uppercase letter “DataProvider”. We add the dataProvider attribute in the @Test Annotation along with the DataProvider’s name. The DataProvider’s name connects both methods and allows the Test Method to receive data. Here’s the code snippet of a dataProvider Attribute and DataProvider Annotation:
@Test (dataProvider = "provideLogInData") public void logIn (String username, String password) throws Exception { driver.findElement(By.linkText("Login")).click(); driver.findElement(By.id("username")).sendKeys(username); driver.findElement(By.id("password")).sendKeys(password); driver.findElement(By.id("tp-sign-in")).click(); String linkLogout = driver.findElement(By.linkText("Logout?")).getText(); Assert.assertEquals(linkLogout, "Logout?", "LogIn Unsuccessful - Please Try Again."); } @DataProvider (name = "provideLogInData") public Object [] [] logInData () { Object [] [] data = new Object [3] [2]; data [0] [0] = "[email protected]"; data [0] [1] = "Password_ABC"; data [1] [0] = "[email protected]"; data [1] [1] = "UseMyValidPassword"; data [2] [0] = "[email protected]"; data [2] [1] = "InvalidPassword"; return data; }
The following is a breakdown of the Test Method:
- @Test (dataProvider = “provideLogInData”) – enables both methods to converse with each other.
- public void logIn (String username, String password) throws Exception – The String username and String password receive each data set from the DataProvider method.
- driver.findElement(By.id(“username”)).sendKeys(username); – send each username as keys to log into TestProject.
- driver.findElement(By.id(“password”)).sendKeys(password); – send each password as keys to log into TestProject.
- assertEquals(linkLogout, “Logout?”, “LogIn Unsuccessful – Please Try Again.”); – verify the user logged into TestProject using a Hard Assert. Assertions were covered in the first article “The Power of TestNG (Test Next Generation)”
One run PASSED and two runs FAILED after executing the same Test Method for three data sets.
dataProviderClass Attribute
The dataProviderClass Attribute permits the DataProvider method and Test Method to reside in different classes. Previously, the DataProvider method and Test Method were in the same class. This time, we will see the dataProviderClass Attribute and dataProvider Attribute operate together. Here’s the code snippet of a Test Method and Data Provider method:
@Test (dataProviderClass = ProvideData.class, dataProvider = "provideLogInData") public void logIn (String username, String password) throws Exception { driver.findElement(By.linkText("Login")).click(); driver.findElement(By.id("username")).sendKeys(username); driver.findElement(By.id("password")).sendKeys(password); driver.findElement(By.id("tp-sign-in")).click(); String linkLogout = driver.findElement(By.linkText("Logout?")).getText(); Assert.assertEquals(linkLogout, "Logout?", "LogIn Unsuccessful - Please Try Again."); }
@DataProvider (name = "provideLogInData") public Object [] [] logInData () { Object [] [] data = new Object [3] [2]; data [0] [0] = "[email protected]"; data [0] [1] = "Password_ABC"; data [1] [0] = "[email protected]"; data [1] [1] = "UseMyValidPassword"; data [2] [0] = "[email protected]"; data [2] [1] = "InvalidPassword"; return data; }
Both attributes must be used together in order to drive data from the Data Provider method to the Test Method via separate classes. If they are not together then a TestNGException is returned when only including a dataProviderClass attribute.
The dataProviderClass Attribute equals the class “ProvideData.class” while the dataProvider Attribute equals the DataProvider’s name “provideLogInData”. All of the username and password data sets remain the same. Therefore, the Test Results have the same PASS and FAIL outcome.
xml File
An xml file stores and carries data for our testing. The following are some of the tags allowed in TestNG’s xml file:
- <suite> – a root tag consisting of one or more test
- <test> – defines which classes will be a part of the execution
- <classes> – most xml files stop at the classes tag which contains a specific class or collection of classes
TestNG also have a parameter tag that helps us perform Data Driven Testing. This is ideal for Cross Browser Testing. Cross Browser Testing is the process of executing one Test Script on multiple browsers at the same time. We are allowed to place the parameter tag within the suite level and/or test level with a name and value. The following is a code snippet of TestNG’s xml containing a parameter tag:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="Cross Browser Testing"> <parameter name = "URL" value = "https://blog.testproject.io/" /> <test name = "Test On Firefox"> <parameter name = "BrowserType" value = "Firefox"/> <classes> <class name = "testproject.blog2.CrossBrowserTesting"/> </classes> </test> <!-- Test On Firefox --> <test name = "Test On Chrome"> <parameter name = "BrowserType" value = "Chrome"/> <classes> <class name = "testproject.blog2.CrossBrowserTesting"/> </classes> </test> <!-- Test On Chrome --> </suite> <!-- Cross Browser Testing -->
Notice there are three parameter tags. One tag located at the suite level and two tags located at the test level. Firefox and Chrome have their own test tag. The parameter tag will get overridden at the test level if the same parameter name is at the suite level. However, this xml file has different parameter names (URL and BrowserType). Here’s a recommendation for determining where to add the parameter tag:
- If each test requires the same value then add the parameter tag at the suite level
- If each test requires a unique value then add the parameter tag at the test level
In our example, each test requires the same website https://blog.testproject.io/ and also has a unique value (Firefox and Chrome).
The Test Method receives all of the values via Parameters Annotation. Therefore, we are going to pass the URL and BrowserType from TestNG’s xml file. The purpose of a Parameters Annotation is to point out how to pass parameters and which parameters to pass to the Test Method. Here’s a code snippet of the Test Method with a Parameters Annotation:
@Test @Parameters ( {"URL", "BrowserType"} ) public void accessTestProjectBlog (String url, String browserType) { if (browserType.equalsIgnoreCase("Firefox")) { System.setProperty("webdriver.gecko.driver", "C:/Users/Rex Allen Jones II/Downloads/Drivers/geckodriver.exe"); driver = new FirefoxDriver (); } else if (browserType.equalsIgnoreCase("Chrome")) { System.setProperty("webdriver.chrome.driver", "C:\\Users\\Rex Allen Jones II\\Downloads\\Drivers\\chromedriver.exe"); driver = new ChromeDriver (); } else { System.out.println("Not A Valid Browser"); } driver.manage().window().maximize(); driver.get(url); System.out.println("\n" + "Open " + browserType); System.out.println(" " + driver.getTitle()); System.out.println(" " + driver.findElement(By.cssSelector("div.join-us h3")).getText()); System.out.println("Close " + browserType + "\n"); driver.quit(); }
Parameters in the annotation (URL, BrowserType) are different from parameters in the Test Method (url, browserType). Parameters in the annotation look up the names via xml file. Parameters in the Test Method receives the values via xml file. The if condition determines whether Firefox or Chrome is the browser for TestProject’s Blog site.
Notice, the @Test Annotation is placed above the @Parameters Annotation. It doesn’t matter which annotation is above or below the other for a successful execution. However, the following two concepts matter if we want to achieve a successful execution:
- Make sure the Parameter’s Annotation values (URL & BrowserType) match xml’s parameter name value
- Make sure to run from the xml file and not the class file
Here’s a few screenshots that show Test Results after executing the xml file.
This article explained Data Driven Testing which utilizes a data source with different data sets as input for a Test Method. The next TestNG article is about Dependency Testing. Check it out here! 😉