Keyword-Driven Cross-Browser tests in Selenium Java Maven with TestNG
This tutorial integrates a Keyword-Driven approach to the Selenium framework created in the tutorial for the Data-Driven approach. The link to the git repository containing the source code of the Data-Driven approach can be found in the blog entry Data-Driven tests in Selenium Java.
In the Data-Driven approach the page objects already contain little function that are used in the test. Nevertheless, the test still performs several actions to verify data and perform actions on the website that have to be written again if another test executes similar actions. The Keyword-Driven approach avoids any actions or verifications within the test but calls functions executing them instead. This way to code is much more maintainable, easier to read and contains fewer redundancies. This tutorial shows how the Keyword-Driven approach can be implemented in the framework.
Table of contents
Add the new keyword files
Remove unused functions from the page objects
Change the test to match the new structure
Download source code
Next step
Add the new keyword files
All keyword files should be saved in a single folder in the framework to give the framework a good structure so the folder src\test\java\com\tws\testframework\keywords has to be created. Within the folder the files OpenPage.java, Search.java and VerifyMainFeatures.java will be created to contain all necessary methods for the test file.
The first keyword class to create is VerifyMainFeatures.java that will contain a function to verify the logo and to verify the footer, because both of these functions can be used within other keywords. Both functions need the WebDriver of the current test to execute them in the correct browser and will perform the action that are already defined in the test. The file should contain the following code:
package com.tws.testframework.keywords;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.WebDriver;
import org.testng.Assert;
import com.tws.testframework.pageobjects.*;
public class VerifyMainFeatures{
public static void verifyLogo(WebDriver driver){
TwsMain poTwsMain = PageFactory.initElements(driver, TwsMain.class);
Assert.assertEquals(true, poTwsMain.logo.isDisplayed());
}
public static void verifyFooter(WebDriver driver){
TwsMain poTwsMain = PageFactory.initElements(driver, TwsMain.class);
Assert.assertEquals("Impressum", poTwsMain.impressum.getText());
Assert.assertEquals("Data protection", poTwsMain.dataProtection.getText());
Assert.assertEquals("About the author", poTwsMain.aboutTheAuthor.getText());
}
}
Next the keyword for opening the main page can be implemented in the file OpenPage.java can be implemented and should contain a method called openTwsMain. This function will receive the WebDriver as a parameter just like the methods in the verification class. The function will open the website and call the function to verify the logo and the footer and should contain the following code:
package com.tws.testframework.keywords;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.WebDriver;
import org.testng.Assert;
import com.tws.testframework.pageobjects.*;
public class OpenPage{
public static void openTwsMain(WebDriver driver){
driver.get("https://test-with-a-smile.de");
TwsMain poTwsMain = PageFactory.initElements(driver, TwsMain.class);
VerifyMainFeatures.verifyLogo(driver);
VerifyMainFeatures.verifyFooter(driver);
}
}
The lass class to implement is the search class that will contain a method to perform the search and a method to verify the search results. Besides the WebDriver both functions need additional parameters to have a search term and to verify the displayed text and should contain the following code:
package com.tws.testframework.keywords;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.WebDriver;
import org.testng.Assert;
import com.tws.testframework.pageobjects.*;
public class Search{
public static void searchForTerm(WebDriver driver, String searchTerm){
TwsMain poTwsMain = PageFactory.initElements(driver, TwsMain.class);
poTwsMain.inp_search.sendKeys(searchTerm);
poTwsMain.btn_search.click();
}
public static void checkFirstSearchResult(WebDriver driver, String searchResultString, String firstResultHeader, String firstResultSummary){
SearchResult poSearchResult = PageFactory.initElements(driver, SearchResult.class);
Assert.assertEquals(searchResultString, poSearchResult.searchResultText.getText());
Assert.assertEquals(firstResultHeader, poSearchResult.firstResultHeader.getText());
Assert.assertEquals(firstResultSummary, poSearchResult.firstResultSummary.getText());
}
}
Remove unused functions from the page objects
By creating the new classes the methods in the page object TwsMain.java are not necessary anymore and can be removed. The new classes perform all the actions themselves and are not bound to one page. After refactoring the code the file TwsMain.java should look like this:
package com.tws.testframework.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 TwsMain {
@FindBy(how = How.XPATH, using = "//*[@id='headimg']/a/img")
@CacheLookup
public WebElement logo;
@FindBy(how = How.XPATH, using = "//*[@id='search-2']/form/label/input")
@CacheLookup
public WebElement inp_search;
@FindBy(how = How.XPATH, using = "//*[@id='search-2']/form/button")
@CacheLookup
public WebElement btn_search;
@FindBy(how = How.ID, using = "impressum")
@CacheLookup
public WebElement impressum;
@FindBy(how = How.ID, using = "dataProtection")
@CacheLookup
public WebElement dataProtection;
@FindBy(how = How.ID, using = "about")
@CacheLookup
public WebElement aboutTheAuthor;
}
Change the test to match the new structure
In the end the test case can be refactored by replacing all action with method calls from the created keyword classes. In the end the test only contains the three calls openTwsMain, searchForTerm and checkFirstSearch result. This way to code of the test is very easy to read and everyone can understand the test even without having knowledge about Selenium or Java. In addition to this the code is easy to maintain and changes to any function will automatically be performed in every test the methods are called. The new source code of the file FirstTest.java will now look like this:
package com.tws.testframework.tests;
import com.tws.testframework.framework.Browser;
import com.tws.testframework.dataprovider.SearchProvider;
import com.tws.testframework.keywords.*;
import org.openqa.selenium.WebDriver;
import org.testng.annotations.Test;
import org.testng.annotations.AfterMethod;
public class FirstTest{
public com.tws.testframework.framework.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);
OpenPage.openTwsMain(browser.driver);
Search.searchForTerm(browser.driver, searchTerm);
Search.checkFirstSearchResult(browser.driver, searchResultString, firstResultHeader, firstResultSummary);
}
@AfterMethod
private void closeBrowsers(){
browser.driver.quit();
}
}
Download source code
You can find the fully commented source code at GitHub:
https://github.com/TestautomationPopp/Keyword-Driven-Selenium-Tests
Next step
To improve this framework the next step is to implement Selenoid and implement a parallel execution in Docker containers