TestNG Creating Selenium Scripts Example
1. Introduction
In this post, we feature a comprehensive article on TestNG Creating Selenium Scripts. TestNG is an open-source automated testing framework for Java unit testing which is inspired by both JUnit and NUnit. It supports the following unit testing features:
- It provides a suite of annotations:
@BeforeClass
,@AfterClass
,@BeforeMethod
,@AfterMethod
,@Test
, etc. - It bundles test classes with
xml
files. @Test
attributes are used to set the exceptions, timeouts, dependencies, and parameterized tests, and are also used to ignore tests.
Selenium is an open-source testing framework for web applications. It supports nine popular browsers: Google Chrome, Internet Explorer, Firefox, Safari, Opera, HtmlUnit, phantomjs, Android, and iOS. It supports several languages: Java, C#, Ruby, Python, and Javascript.
In this example, I will write automated testing scripts using Java with TestNG and Selenium for the following web sites:
- Google Search Home Page
- Google Search Results Page
- Google Gmail New Account Page
2. Technologies Used
The example code in this article was built and run using:
- Java 11
- Maven 3.3.9
- Eclipse Oxygen
- TestNg 6.8
- Selenium 3.14
3. Set up
3.1 Install TestNG Plug-in in Eclipse IDE
You can verify that the TestNG is installed in Eclipse IDE by finding it from the Installation Details.
Click here for detailed instructions on how to install it.
3.2 Install Google Chrome Web driver
I will download the Selenium Chrome WebDriver
from here and install it to my PC at C:\MaryZheng\DevTools\Selenium
. This location will be used to set the "webdriver.chrome.driver"
system property before initializing a ChromeDriver
instance.
3.3 Create a Maven Project
Create a Maven project which includes both TestNG and Selenium dependencies.
pom.xml
<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>testng-selenium-example</groupId> <artifactId>testng-selenium-example</artifactId> <version>0.0.1-SNAPSHOT</version> <build> <sourceDirectory>src</sourceDirectory> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> <configuration> <release>11</release> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>6.8</version> </dependency> <!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java --> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>3.141.59</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-io --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> </dependency> </dependencies> </project>
4. Test Classes
4.1 SeleniumTestBase
In this step, I will create a SeleniumTestBase
class which has three methods:
setupWebDriver
– this method is annotated with the@BeforeClass
annotation which will be executed once before the first test method in the current class is executed. It sets up ChromeWebDriver
and opens the Google home page.cleanup
– this method is annotated with the@AfterClass
annotation which will be executed once after all the test methods in the current class are executed. It closes the Chrome browser window and quits.saveScreenshot
– this method is annotated with the@AfterMethod
annotation which will be executed after each test method. It copies the screenshot to a file.
SeleniumTestBase.java
package jcg.zheng.testngdemo; import java.io.File; import java.io.IOException; import java.util.concurrent.TimeUnit; import org.apache.commons.io.FileUtils; import org.openqa.selenium.OutputType; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.support.ui.WebDriverWait; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; public class SeleniumTestBase { protected static final String GOOGLE_URL = "http://google.com"; protected String screenshotFileName = null; protected WebDriver driver;// an API to send commands directly to the browser protected WebDriverWait webdriverwait; @BeforeClass public void setupWebDriver() { System.setProperty("webdriver.chrome.driver", "C:\\MaryZheng\\DevTools\\Selenium\\chromedriver.exe"); driver = new ChromeDriver(); webdriverwait = new WebDriverWait(driver, 30); driver.manage().deleteAllCookies(); driver.manage().window().maximize(); driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS); driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS); driver.get(GOOGLE_URL); } @AfterClass public void cleanup() { driver.close(); driver.quit(); } @AfterMethod public void saveScreenshot() throws IOException { if (screenshotFileName != null) { File screeshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE); FileUtils.copyFile(screeshot, new File(screenshotFileName)); } } }
4.2 GoogleSearchTest
In this step, I will use Chrome’s developer tool to find the web element’s id and name. I will create a GoogleSearchTest
class which has six methods:
check_title
– checks that the Google search home page’s title is “Google” via Selenium’sdriver.getTitle()
method and sets this method’s timeout to 10 seconds via@Test(timeout = 10000)
.check_feeling_lucky
– checks that the Google search home page has an element with id value of “gbqfbb” viadriver.findElement(By.id("gbqfbb")
).check_about_link
– checks that theAbout
link is displayed via the isDisplayed method and groups it under “links” group via@Test(groups="links")
.check_store_link
– checks that theStore
link is displayed and groups it under “links” group.check_gmail_link
– checks that theGmail
link is displayed and groups it under “links” group.check_images_link
– checks that theImages
link is displayed and groups it under “links” group.
GoogleSearchTest.java
package jcg.zheng.testngdemo; import static org.junit.Assert.assertTrue; import static org.testng.Assert.assertEquals; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.testng.annotations.Test; public class GoogleSearchTest extends SeleniumTestBase { @Test(timeOut = 10000) public void check_title() { String title = driver.getTitle(); assertEquals("Google", title); } @Test public void check_feeling_lucky() { WebElement searchInput = driver.findElement(By.id("gbqfbb")); assertTrue(searchInput.isDisplayed()); } @Test(groups = "links") public void check_about_link() { WebElement aboutLink = driver.findElement(By.linkText("About")); assertTrue(aboutLink.isDisplayed()); } @Test(groups = "links") public void check_store_link() { WebElement aboutLink = driver.findElement(By.linkText("Store")); assertTrue(aboutLink.isDisplayed()); } @Test(groups = "links") public void check_gmail_link() { WebElement aboutLink = driver.findElement(By.linkText("Gmail")); assertTrue(aboutLink.isDisplayed()); } @Test(groups = "links") public void check_images_link() { WebElement aboutLink = driver.findElement(By.linkText("Images")); assertTrue(aboutLink.isDisplayed()); } }
Select the GoogleSearchTest
file in Eclipse IDE and right-clicking the “Run as -> TestNG Test”. Capture the output.
Test Output
[RemoteTestNG] detected TestNG version 6.8.0 [TestNG] Running: C:\Windows\Temp\testng-eclipse-1768898921\testng-customsuite.xml Starting ChromeDriver 74.0.3729.6 (255758eccf3d244491b8a1317aa76e1ce10d57e9-refs/branch-heads/3729@{#29}) on port 35888 Only local connections are allowed. Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code. Jun 04, 2019 9:17:55 PM org.openqa.selenium.remote.ProtocolHandshake createSession INFO: Detected dialect: OSS PASSED: check_about_link PASSED: check_feeling_lucky PASSED: check_gmail_link PASSED: check_images_link PASSED: check_store_link PASSED: check_title =============================================== Default test Tests run: 6, Failures: 0, Skips: 0 =============================================== =============================================== Default suite Total tests run: 6, Failures: 0, Skips: 0 =============================================== [TestNG] Time taken by org.testng.reporters.SuiteHTMLReporter@1817d444: 247 ms [TestNG] Time taken by org.testng.reporters.JUnitReportReporter@130161f7: 18 ms [TestNG] Time taken by org.testng.reporters.XMLReporter@7ed7259e: 82 ms [TestNG] Time taken by org.testng.reporters.jq.Main@1725dc0f: 123 ms [TestNG] Time taken by [FailedReporter passed=0 failed=0 skipped=0]: 0 ms [TestNG] Time taken by org.testng.reporters.EmailableReporter@41fbdac4: 8 ms
4.3 GoogleSearchResultTest
TestNG provides the dependsOnMethods
attribute at @Test
annotation to specify its depended methods. In this step, I will create three test methods and set up the dependencies among them.
check_google_search_button
– verifies that the search button is enabled via theisEnabled()
method.check_google_search_input
– verifies that the search input box is displayed and invokes itssendKeys("Mary")
to populate the input data with “Mary”.search_results
– sets this test method depends on bothcheck_google_search_button
andcheck_google_search_input
. It will execute only the depended methods pass.
GoogleSearchResultTest.java
package jcg.zheng.testngdemo; import static org.junit.Assert.assertTrue; import static org.testng.Assert.assertEquals; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.testng.annotations.Test; public class GoogleSearchResultTest extends SeleniumTestBase { @Test public void check_google_search_input() { WebElement searchInput = driver.findElement(By.name("q")); assertTrue(searchInput.isDisplayed()); searchInput.sendKeys("Mary"); screenshotFileName = "search_Mary.png"; } @Test public void check_google_search_button() { WebElement searchBtn = driver.findElement(By.name("btnK")); assertTrue(searchBtn.isEnabled()); } @Test(dependsOnMethods = { "check_google_search_input", "check_google_search_button" }) public void search_results() { WebElement searchBtn = driver.findElement(By.name("btnK")); searchBtn.click(); screenshotFileName = "search_Mary_result.png"; assertEquals("Mary - Google Search", driver.getTitle()); } }
Select the GoogleSearchResultTest
file in Eclipse IDE and right-clicking the “Run as -> TestNG Test”. Capture the output.
Test Output
[RemoteTestNG] detected TestNG version 6.8.0 [TestNG] Running: C:\Windows\Temp\testng-eclipse--1473354869\testng-customsuite.xml Starting ChromeDriver 74.0.3729.6 (255758eccf3d244491b8a1317aa76e1ce10d57e9-refs/branch-heads/3729@{#29}) on port 9517 Only local connections are allowed. Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code. Jun 04, 2019 9:27:27 PM org.openqa.selenium.remote.ProtocolHandshake createSession INFO: Detected dialect: OSS PASSED: check_google_search_button PASSED: check_google_search_input PASSED: search_results =============================================== Default test Tests run: 3, Failures: 0, Skips: 0 =============================================== =============================================== Default suite Total tests run: 3, Failures: 0, Skips: 0 =============================================== [TestNG] Time taken by org.testng.reporters.SuiteHTMLReporter@1817d444: 188 ms [TestNG] Time taken by org.testng.reporters.JUnitReportReporter@130161f7: 12 ms [TestNG] Time taken by org.testng.reporters.XMLReporter@7ed7259e: 26 ms [TestNG] Time taken by org.testng.reporters.jq.Main@1725dc0f: 146 ms [TestNG] Time taken by [FailedReporter passed=0 failed=0 skipped=0]: 0 ms [TestNG] Time taken by org.testng.reporters.EmailableReporter@41fbdac4: 9 ms
4.4 SearchMoreThanOnceTest
TestNG provides the invocationCount
attribute to the @Test
annotation which can be used to execute the same test multiple times.
In this step, I will create a check_google_search_results
method which searches “Mary Zheng” ten times. I also add @BeforeMethod
to navigate it back to the Google home page.
SearchMoreThanOnceTest.java
package jcg.zheng.testngdemo; import static org.junit.Assert.assertTrue; import static org.testng.Assert.assertEquals; import java.util.Random; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class SearchMoreThanOnceTest extends SeleniumTestBase { @Test(invocationCount = 10) public void check_google_search_results() { WebElement searchInput = driver.findElement(By.name("q")); assertTrue(searchInput.isDisplayed()); searchInput.sendKeys("Mary Zheng"); WebElement searchBtn = driver.findElement(By.name("btnK")); searchBtn.click(); Random random = new Random(); screenshotFileName = "search_MaryZheng_" + random.nextInt(10) + ".png"; assertEquals("Mary Zheng - Google Search", driver.getTitle()); } @BeforeMethod public void backToSearch() { driver.get(GOOGLE_URL); } }
Select the SearchMoreThanOnceTest
file in Eclipse IDE and right-clicking the “Run as -> TestNG Test”. Capture the output.
Test Output
[RemoteTestNG] detected TestNG version 6.8.0 [TestNG] Running: C:\Windows\Temp\testng-eclipse--1432373915\testng-customsuite.xml Starting ChromeDriver 74.0.3729.6 (255758eccf3d244491b8a1317aa76e1ce10d57e9-refs/branch-heads/3729@{#29}) on port 17724 Only local connections are allowed. Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code. Jun 04, 2019 9:30:13 PM org.openqa.selenium.remote.ProtocolHandshake createSession INFO: Detected dialect: OSS PASSED: check_google_search_results PASSED: check_google_search_results PASSED: check_google_search_results PASSED: check_google_search_results PASSED: check_google_search_results PASSED: check_google_search_results PASSED: check_google_search_results PASSED: check_google_search_results PASSED: check_google_search_results PASSED: check_google_search_results =============================================== Default test Tests run: 10, Failures: 0, Skips: 0 =============================================== =============================================== Default suite Total tests run: 10, Failures: 0, Skips: 0 =============================================== [TestNG] Time taken by org.testng.reporters.SuiteHTMLReporter@1817d444: 376 ms [TestNG] Time taken by org.testng.reporters.JUnitReportReporter@130161f7: 18 ms [TestNG] Time taken by org.testng.reporters.XMLReporter@7ed7259e: 65 ms [TestNG] Time taken by org.testng.reporters.jq.Main@1725dc0f: 132 ms [TestNG] Time taken by [FailedReporter passed=0 failed=0 skipped=0]: 1 ms [TestNG] Time taken by org.testng.reporters.EmailableReporter@41fbdac4: 15 ms
4.5 GmailTest
In this step, I will create a GmailTest
class which has two methods:
check_gmail_link
– it finds the Gmail link from the Google home page and verifies that the title is “Gmail – Free Storage and Email from Google” after clicking it.find_not_exist_link
– it will throwNoSuchElementException
when finding non-existing web elements. TestNG handles it via theexpectedExceptions
attribute.
GmailTest.java
package jcg.zheng.testngdemo; import static org.junit.Assert.assertTrue; import static org.testng.Assert.assertEquals; import org.openqa.selenium.By; import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.WebElement; import org.testng.annotations.Test; public class GmailTest extends SeleniumTestBase { @Test public void check_gmail_link() { WebElement gmailLink = driver.findElement(By.linkText("Gmail")); assertTrue(gmailLink.isDisplayed()); gmailLink.click(); screenshotFileName = "gmail_page.png"; String gmailTitle = driver.getTitle(); assertEquals("Gmail - Free Storage and Email from Google", gmailTitle); } @Test(expectedExceptions = NoSuchElementException.class) public void find_not_exist_Link() { driver.findElement(By.linkText("mail")); } }
Select the GmailTest
file in Eclipse IDE and right-clicking to “Run as -> TestNG Test”. Capture the output.
Test Output
[RemoteTestNG] detected TestNG version 6.8.0 [TestNG] Running: C:\Windows\Temp\testng-eclipse-1469233723\testng-customsuite.xml Starting ChromeDriver 74.0.3729.6 (255758eccf3d244491b8a1317aa76e1ce10d57e9-refs/branch-heads/3729@{#29}) on port 20002 Only local connections are allowed. Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code. Jun 04, 2019 9:32:26 PM org.openqa.selenium.remote.ProtocolHandshake createSession INFO: Detected dialect: OSS PASSED: check_gmail_link PASSED: find_not_exist_Link =============================================== Default test Tests run: 2, Failures: 0, Skips: 0 =============================================== =============================================== Default suite Total tests run: 2, Failures: 0, Skips: 0 =============================================== [TestNG] Time taken by org.testng.reporters.SuiteHTMLReporter@1817d444: 178 ms [TestNG] Time taken by org.testng.reporters.JUnitReportReporter@130161f7: 15 ms [TestNG] Time taken by org.testng.reporters.XMLReporter@7ed7259e: 31 ms [TestNG] Time taken by org.testng.reporters.jq.Main@1725dc0f: 122 ms [TestNG] Time taken by [FailedReporter passed=0 failed=0 skipped=0]: 0 ms [TestNG] Time taken by org.testng.reporters.EmailableReporter@41fbdac4: 12 ms
4.6 GmailNewAccountsTest
TestNG supports a parameterized test with a @DataProvider
annotation along with the dataProvider
attribute. In this step, I will create a GmailNewAccountsTest
class which creates three new Gmail accounts with the createGmailUsers
method.
Selenium web driver provides WebDriverWait
to wait for the page before applying any action on the web elements.
GmailNewAccountsTest.java
package jcg.zheng.testngdemo; import java.util.ArrayList; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ExpectedConditions; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class GmailNewAccountsTest extends SeleniumTestBase { @Test(dataProvider = "setGmailUsers") public void createGmailUsers(String firstName, String lastName, String username, String pwd) throws InterruptedException { WebElement gmailLink = driver.findElement(By.linkText("Gmail")); gmailLink.click(); WebElement createAcctBtn = webdriverwait .until(ExpectedConditions.elementToBeClickable(By.linkText("Create an account"))); createAcctBtn.click(); webdriverwait.until(ExpectedConditions.numberOfWindowsToBe(2)); ArrayList<String> windowsTabs = new ArrayList<>(driver.getWindowHandles()); driver.switchTo().window(windowsTabs.get(windowsTabs.size() - 1)); // switch to the new tab Thread.sleep(2000); WebElement fnameEle = webdriverwait .until(ExpectedConditions.elementToBeClickable(By.id("firstName"))); fnameEle.sendKeys(firstName); WebElement lnameEle = webdriverwait .until(ExpectedConditions.elementToBeClickable(By.id("lastName"))); lnameEle.sendKeys(lastName); WebElement unameEle = webdriverwait .until(ExpectedConditions.elementToBeClickable(By.id("username"))); unameEle.sendKeys(username); WebElement pwdEle = webdriverwait .until(ExpectedConditions.elementToBeClickable(By.name("Passwd"))); pwdEle.sendKeys(pwd); driver.close(); driver.switchTo().window(windowsTabs.get(0));// switch back to the main Thread.sleep(2000); } @DataProvider public Object[][] setGmailUsers() { return new Object[][] { { "firstName", "lastname", "flname", "pwd" }, { "Mary", "Zheng", "mzheng", "pwd2" }, { "Allen", "Zheng", "aZheng", "pwd3" } }; } }
Test Output
Select the GmailNewAccountsTest
file in Eclipse IDE and right-clicking the “Run as -> TestNG Test”. Capture the output.
[RemoteTestNG] detected TestNG version 6.8.0 [TestNG] Running: C:\Windows\Temp\testng-eclipse-707167101\testng-customsuite.xml Starting ChromeDriver 74.0.3729.6 (255758eccf3d244491b8a1317aa76e1ce10d57e9-refs/branch-heads/3729@{#29}) on port 20723 Only local connections are allowed. Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code. Jun 04, 2019 9:34:10 PM org.openqa.selenium.remote.ProtocolHandshake createSession INFO: Detected dialect: OSS PASSED: createGmailUsers("firstName", "lastname", "flname", "pwd") PASSED: createGmailUsers("Mary", "Zheng", "mzheng", "pwd2") PASSED: createGmailUsers("Allen", "Zheng", "aZheng", "pwd3") =============================================== Default test Tests run: 3, Failures: 0, Skips: 0 =============================================== =============================================== Default suite Total tests run: 3, Failures: 0, Skips: 0 =============================================== [TestNG] Time taken by org.testng.reporters.SuiteHTMLReporter@1817d444: 186 ms [TestNG] Time taken by org.testng.reporters.JUnitReportReporter@130161f7: 12 ms [TestNG] Time taken by org.testng.reporters.XMLReporter@7ed7259e: 33 ms [TestNG] Time taken by org.testng.reporters.jq.Main@1725dc0f: 144 ms [TestNG] Time taken by [FailedReporter passed=0 failed=0 skipped=0]: 0 ms [TestNG] Time taken by org.testng.reporters.EmailableReporter@41fbdac4: 5 ms
5. Test Suite XML
TestNG groups a suite of test classes in a XML file. Eclipse TestNG plugin auto-generates the xml for the test classes after right-clicking “Run as -> TestNG Test”. TestNG will generate a set of reports for the testing results. Here is my project which shows
5.1 TestNG_google.xml
In this step, I will create a TestNG_google.xml
to bundle two tests:
- Google Search Test – bundles three testing classes:
GoogleSearchTest
,GoogleSearchResult
, andSearchMoreThanOnceTest
. - Gmail Test – includes
GmailTest
.
TestNG_google.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="Google Search Suites"> <test name="Google Search Test" verbose="2"> <classes> <class name="jcg.zheng.testngdemo.GoogleSearchTest" /> <class name="jcg.zheng.testngdemo.GoogleSearchResultTest" /> <class name="jcg.zheng.testngdemo.SearchMoreThanOnceTest"> <methods> <include name="check_google_search_results" /> </methods> </class> <!-- jcg.zheng.testngdemo.SearchMoreThanOnceTest --> </classes> </test> <test name="Gmail Test" verbose="2"> <classes> <class name="jcg.zheng.testngdemo.GmailTest" /> </classes> </test> <!-- Default test --> </suite> <!-- Default suite -->
Select TestNG_google.xml
file and right-clicking “Run as -> TestNG Suite”. It will execute the tests and output the results. It also generates the HTML reports. Here is the HTML report screenshot.
5.2 TestNG_gmail.xml
In this step, I will create a TestNG_gmail.xml
to bundle both GmailTest
and GmailNewAccountsTest
classes. It also sets up the timeout to 1 minute for the test suite.
TestNG_gmail.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="Gmail suite" time-out="60000"> <test name="Gmail test" verbose="2"> <classes> <class name="jcg.zheng.testngdemo.GmailTest"/> <class name="jcg.zheng.testngdemo.GmailNewAccountsTest" /> </classes> </test> </suite>
Select TestNG_gmail.xml
file and right-clicking “Run as -> TestNG Suite”. It will execute the tests and output the results. It also generates the HTML reports. Here is the HTML report screenshot.
6. TestNG Creating Selenium Scripts – Summary
In this article, I created automation test scripts for Google web sites using both Selenium and TestNG.
7. Download the Source Code
This tutorial consists of a Maven project which created automated Selenium scripts to test the Google Web sites.
You can download the full source code of this example here: TestNG Framework Creating Selenium Scripts Example