Complete Guide On TestNG Annotations For Selenium WebDriver
TestNG is a testing framework created by Cédric Beust and helps to cater a lot of our testing needs. It is widely used in Selenium. Wondering on what NG stands for? Well, it refers to ‘Next Generation’. TestNG is similar to Junit but is more powerful to it when it comes to controlling the execution flow of your program. As the nature of framework, we tend to make our tests more structured and provides better validation points through the use of TestNG.
Some of the noteworthy features of TestNG are:
- Powerful and wide variety of annotations to support your test cases.
- Helps to perform parallel testing, dependent method testing.
- Flexibility of running your tests through multiple sets of data through TestNG.xml file or via data-provider concept.
- Test cases can be grouped and prioritized as per need basis.
- Provides access to HTML reports and can be customized through various plugins.
- Test logs can be generated across tests.
- Can be easily integrated with eclipse, Maven, Jenkins etc.
A basic process flow of a TestNG programs involves the following steps:
So, before jumping onto the annotations in TestNG for Selenium, it would be better to refer the prerequisites are required to setup TestNG.
Prerequisites
- Java Development Kit
- Setup Eclipse or any other IDE.
- Install TestNG in Eclipse or any other IDE.
Note: Annotations can be used only with Java version 1.5 or higher.
If you are new to TestNG framework then follow our guide to run your first automation script with TestNG.
Run TestNG Selenium Scripts On Cloud Grid
So, What Is An Annotation?
An annotation is a tag that provides additional information about the class or method. It is represented by ‘@’ prefix. TestNG use these annotations to help in making a robust framework. Let us have a look at these annotations of TestNG for automation testing with Selenium.
@Test
The most important annotation in TestNG framework where the main business logic resides. All functionalities to be automated are kept inside the @Test annotation method. It has various attributes based on which the method can be reformed and executed.
Example of a code snippet below validating the url :
@Test public void testCurrentUrl() throws InterruptedException { driver.findElement(By.xpath("//*[@id='app']/header/aside/ul/li[4]/a")).click(); String currentUrl= driver.getCurrentUrl(); assertEquals(current_url, "https://automation.lambdatest.com/timeline/?viewType=build&page=1", "url did not matched"); }
@BeforeTest
This annotation is run before your first @Test annotation method in your class. You can use this annotation in TestNG for Selenium to setup your browser profile preferences, for example auto opening your browser in maximize mode, setting up your own customized profile for your browser etc.
Below is the code snippet for BeforeTest method ensuring the browser opens in maximize mode:
@BeforeTest public void profileSetup() { driver.manage().window().maximize(); }
@AfterTest
This annotation in TestNG runs after all your test methods belonging to your class have run. This is a useful annotation which comes handy in terms of reporting your automation results to your stakeholders. You can use this annotation to generate report of your tests and share it to your stakeholders via email.
Example of the code snippet below:
@AfterTest public void reportReady() { System.out.println("Report is ready to be shared, with screenshots of tests"); }
@BeforeMethod
This annotation in TestNG runs before every @test annotated method. You can use it to check out for the database connections before executing your tests or lets say different functionality been tested in your @test annotated method which requires user login in a certain class. In this case also you can put your login code in the @BeforeMethod annotation method.
Below code snippet is an example, displaying login functionality of the LambdaTest platform:
@BeforeMethod public void checkLogin() { driver.get("https://accounts.lambdatest.com/login"); driver.findElement(By.xpath("//input[@name='email']")).sendKeys("sadhvisingh24@gmail.com"); driver.findElement(By.xpath("//input[@name='password']")).sendKeys("XXXXX"); driver.findElement(By.xpath("//*[@id='app']/section/form/div/div/button")).click(); }
@AfterMethod
This annotation runs after every @test annotated method. This annotation can be used to take screenshots of every test method ran against test runs .
Below code snippet indicating screenshot taken in the @AfterTest annotation in TestNG for Selenium:
@AfterMethod public void screenShot() throws IOException { TakesScreenshot scr= ((TakesScreenshot)driver); File file1= scr.getScreenshotAs(OutputType.FILE); FileUtils.copyFile(file1, new File("C:\\Users\\navyug\\workspace\\QAPractise\\test-output\\test1.PNG")); }
@BeforeClass
This annotation runs before the first test method in the current class.This annotation can be used to setup your browser properties, initialize your driver, opening your browser with the desired URL etc.
Below is the code snippet for BeforeClass:
@BeforeClass public void appSetup() { driver.get(url); }
@AfterClass
This annotation runs after the last test method in the current class. This annotation in TestNG can be used to perform clean up activities during your tests like closing your driver etc
Below is the example of code snippet showing closing activities performed:
@AfterClass public void closeUp() { driver.close(); }
@BeforeSuite
A suite can consist of multiple classes, this annotation runs before all the tests methods of all the classes. This annotation marks the entry point of execution. @BeforeSuite annotation in TestNG can be used to perform the needed and generic functions like setting up and starting Selenium drivers or remote web drivers etc.
Example of @BeforeSuite annotation in TestNG, code snippet showcasing setting up of driver:
@BeforeSuite public void setUp() { System.setProperty("webdriver.chrome.driver", "path to chrome driver"); driver=new ChromeDriver(); }
@AfterSuite
This annotation in TestNG runs post all the test methods of all the classes have run. This annotation can be used to clean up the processes before completing off your tests when you have multiple classes in functioning, for example closing the drivers etc.
Below is the code snippet for @AfterSuite annotation in TestNG for Selenium:
@AfterSuite public void cleanUp() { System.out.println("All close up activities completed"); }
@BeforeGroups
TestNG helps testers create a bunch of tests into groups through the attribute group used in the @Test annotation. For example, if you wish all similar functionalities related to user management to be clubbed together, you can mark all tests like Dashboard, profile, transactions etc. into a single group as ‘user_management’. This @BeforeGroups annotation in TestNG helps to run the defined test first before the specified group. This annotation can be used if the group focuses on a single functionality like stated in the above example. The BeforeGroup annotation can contain the login feature which is required to run before any other methods like user dashboard, user profile etc.
Example of the Code snippet for @BeforeGroups annotation in TestNG for Selenium:
@BeforeGroups("urlValidation") public void setUpSecurity() { System.out.println("url validation test starting"); }
@AfterGroups
This annotation in TestNG runs after all the test methods of the specified group are executed.
Example of Code snippet for @AfterGroups annotation in TestNG for Selenium:
@AfterGroups("urlValidation") public void tearDownSecurity() { System.out.println("url validation test finished"); } The below code displays an example of all annotations used along with TestNG report respectively: import static org.testng.Assert.assertEquals; import java.io.File; import java.io.IOException; import java.util.concurrent.TimeUnit; import org.apache.commons.io.FileUtils; import org.openqa.selenium.By; import org.openqa.selenium.OutputType; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterGroups; import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterSuite; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeGroups; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeSuite; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; public class AnnotationsTestNG { public WebDriver driver; public String url="https://www.lambdatest.com/"; @BeforeSuite public void setUp() { System.setProperty("webdriver.chrome.driver", "C:\\Users\\navyug\\workspace\\QAPractise\\src\\ChromeDriver\\chromedriver.exe"); driver=new ChromeDriver(); driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS); System.out.println("The setup process is completed"); } @BeforeTest public void profileSetup() { driver.manage().window().maximize(); System.out.println("The profile setup process is completed"); } @BeforeClass public void appSetup() { driver.get(url); System.out.println("The app setup process is completed"); } @BeforeMethod public void checkLogin() { driver.get("https://accounts.lambdatest.com/login"); driver.findElement(By.xpath("//input[@name='email']")).sendKeys("sadhvisingh24@gmail.com"); driver.findElement(By.xpath("//input[@name='password']")).sendKeys("activa9049"); driver.findElement(By.xpath("//*[@id='app']/section/form/div/div/button")).click(); System.out.println("The login process on lamdatest is completed"); } @Test(groups="urlValidation") public void testCurrentUrl() throws InterruptedException { driver.findElement(By.xpath("//*[@id='app']/header/aside/ul/li[4]/a")).click(); Thread.sleep(6000); String currentUrl= driver.getCurrentUrl(); assertEquals(currentUrl, "https://automation.lambdatest.com/timeline/?viewType=build&page=1", "url did not matched"); System.out.println("The url validation test is completed"); } @AfterMethod public void screenShot() throws IOException { TakesScreenshot scr= ((TakesScreenshot)driver); File file1= scr.getScreenshotAs(OutputType.FILE); FileUtils.copyFile(file1, new File("C:\\Users\\navyug\\workspace\\QAPractise\\test-output\\test1.PNG")); System.out.println("Screenshot of the test is taken"); } @AfterClass public void closeUp() { driver.close(); System.out.println("The close_up process is completed"); } @AfterTest public void reportReady() { System.out.println("Report is ready to be shared, with screenshots of tests"); } @AfterSuite public void cleanUp() { System.out.println("All close up activities completed"); } @BeforeGroups("urlValidation") public void setUpSecurity() { System.out.println("url validation test starting"); } @AfterGroups("urlValidation") public void tearDownSecurity() { System.out.println("url validation test finished"); } }
TestNG Report:
Console Output:
Execution Sequence Of Annotations In TestNG For Selenium
All annotations described above are executed on runtime in the following order:
- BeforeSuite
- BeforeTest
- BeforeClass
- BeforeGroups
- BeforeMethod
- Test
- AfterMethod
- AfterGroups
- AfterClass
- AfterTest
- AfterSuite
Here is an image of the basic workflow of these annotations:
Attributes Used With Annotations In TestNG
These test annotations in TestNG have multiple attributes that can be used for our test method. The attributes further help in defining our tests and help in providing clarity in terms of execution flow of the different test’s method used in the TestNG class. Listing them below:
- Description: It defines the test method. One can define what a method does via the description. For example,
@Test(description=”this test validates the login functionality”)
. - alwaysRun: this attribute when used with a test method ensures it always run irrespective of the fact even if the parameters on which the method depends fails. When the value is set to true this method will always execute. For example, @Test(alwaysRun= true).
- dataProvider: This attribute is set to provide data from the dataProvider annotated test to the test provided with this attribute. For example, let’s say you intent to run your tests on multiple cross browsers, where a dataProvider annotated test is written which contains multiple inputs of browsers and their corresponding versions. In this case the test containing this attribute will use those inputs of data to run you tests on multiple browsers. Syntax for the same is, @Test(dataProvider=”cross browser testing”).
- dependsOnMethods: This attribute provides details to the execution flow, wherein the test is executed only if its dependent method mentioned in the attribute is executed. In case the test on which the method depends on is failed or not executed, the test is skipped from the execution. For example, @Test(dependsOnmethod=”Login”).
- groups: This attribute helps to groups your test methods focusing onto a single functionality into one group. For example @Test(groups=”Payment_Module”). This attribute also helps in the longer run when one can choose to ignore few groups during the execution cycle and chose over the other groups. All one need to do is mention the included groups in the TestNG.xml file within the include tag whereas the excluded groups can be defined using the exclude tag in the xml file.
- dependsOnGroups: this attribute performs the above two attributes functions in collation i.e. it defines the test method with the attribute ‘dependsOn’ the defined groups. Once that group of tests are run, only post that this annotated method would execute. For example, @Test(dependsOnMethods = “Payment_Module” ).
- priority: This attribute helps us to defined priority of the test’s methods. When TestNG executes the @Test annotated method, it may do so in random order. In a scenario where you wish that your @Test annotated method runs in a desired sequence you can use the priority attribute. The default priority of all test methods is 0. Priorities in ascending order are scheduled first for execution for example, @Test(priority=1), @Test(priority=2), in this case test with priority equal to one will be executed first then the test with priority as 2.
- enabled: This attribute comes into picture, when you have an intent to ignore a particular test method and don’t want to execute it. All you need to do is set this attribute to false. For example, @Test(enabled= false).
- timeout: This attribute helps to define the time a particular test should take to execute, in case it exceeds the time defined by the attribute, the test method would terminate and will fail with an exception marked as org.testng.internal.thread.ThreadTimeoutException. For example, @Test(timeOut= 500). Please note the time specified is in milliseconds.
- InvocationCount: This attribute works exactly like the loop. Based on the attribute set across the test method, it would execute that method those number of times. For example, @Test(invocationCount = 5), this would execute the test 5 times.
- InvocationTimeOut: this attribute is used in unison with the above invocationCount attribute. Based on the set value of this attribute along with the invocationCount, this ensures the test runs the number of times specified as per the invocationCount in the defined time set by the invocationTimeOut attribute. For example, @Test(invocationCount =5,invocationTimeOut = 20 ).
- expectedExceptions: this attribute helps to handle the exception the test method is expected to throw. In case the one defined in the attribute is set and thrown by the test method it is passed else any other exception not stated in the attribute and thrown by the test method, would make the test method fail. For example, @Test(expectedExceptions = {ArithmeticException.class }).
The above defined are the attributes used with the annotations in TestNG for Selenium. Below is the code snippet showcasing the use of the above attributes:
import static org.testng.Assert.assertEquals; import java.io.File; import java.io.IOException; import java.util.concurrent.TimeUnit; import org.apache.commons.io.FileUtils; import org.openqa.selenium.By; import org.openqa.selenium.OutputType; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterGroups; import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterSuite; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeGroups; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeSuite; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; public class AnnotationsTest { public WebDriver driver; public String url="https://www.lambdatest.com/"; @BeforeSuite public void setUp() { System.setProperty("webdriver.chrome.driver", "C:\\Users\\navyug\\workspace\\QAPractise\\src\\ChromeDriver\\chromedriver.exe"); driver=new ChromeDriver(); System.out.println("The setup process is completed"); } @BeforeTest public void profileSetup() { driver.manage().window().maximize(); System.out.println("The profile setup process is completed"); } @BeforeClass public void appSetup() { driver.get(url); System.out.println("The app setup process is completed"); } @Test(priority=2) public void checkLogin() { driver.get("https://accounts.lambdatest.com/login"); driver.findElement(By.xpath("//input[@name='email']")).sendKeys("sadhvisingh24@gmail.com"); driver.findElement(By.xpath("//input[@name='password']")).sendKeys("xxxxx"); driver.findElement(By.xpath("//*[@id='app']/section/form/div/div/button")).click(); System.out.println("The login process on lamdatest is completed"); } @Test(priority=0 ,description= "this test validates the sign-up test") public void signUp() throws InterruptedException { WebElement link= driver.findElement(By.xpath("//a[text()='Free Sign Up']")); link.click(); WebElement organization=driver.findElement(By.xpath("//input[@name='organization_name']")); organization.sendKeys("LambdaTest"); WebElement firstName=driver.findElement(By.xpath("//input[@name='name']")); firstName.sendKeys("Test"); WebElement email=driver.findElement(By.xpath("//input[@name='email']")); email.sendKeys("User622@gmail.com"); WebElement password=driver.findElement(By.xpath("//input[@name='password']")); password.sendKeys("TestUser123"); WebElement phoneNumber=driver.findElement(By.xpath("//input[@name='phone']")); phoneNumber.sendKeys("9412262090"); WebElement termsOfService=driver.findElement(By.xpath("//input[@name='terms_of_service']")); termsOfService.click(); WebElement button=driver.findElement(By.xpath("//button[text()='Signup']")); button.click(); } @Test(priority=3, alwaysRun= true, dependsOnMethods="check_login", description="this test validates the URL post logging in" , groups="url_validation") public void testCurrentUrl() throws InterruptedException { driver.findElement(By.xpath("//*[@id='app']/header/aside/ul/li[4]/a")).click(); String currentUrl= driver.getCurrentUrl(); assertEquals(current_url, "https://automation.lambdatest.com/timeline/?viewType=build&page=1", "url did not matched"); System.out.println("The url validation test is completed"); } @Test(priority=1, description = "this test validates the logout functionality" ,timeOut= 25000) public void logout() throws InterruptedException { Thread.sleep(6500); driver.findElement(By.xpath("//*[@id='userName']")).click(); driver.findElement(By.xpath("//*[@id='navbarSupportedContent']/ul[2]/li/div/a[5]")).click(); } @Test(enabled=false) public void skipMethod() { System.out.println("this method will be skipped from the test run using the attribute enabled=false"); } @Test(priority=6,invocationCount =5,invocationTimeOut = 20) public void invocationcountShowCaseMethod() { System.out.println("this method will be executed by 5 times"); } @AfterMethod() public void screenshot() throws IOException { TakesScreenshot scr= ((TakesScreenshot)driver); File file1= scr.getScreenshotAs(OutputType.FILE); FileUtils.copyFile(file1, new File("C:\\Users\\navyug\\workspace\\QAPractise\\test-output\\test1.PNG")); System.out.println("Screenshot of the test is taken"); } @AfterClass public void closeUp() { driver.close(); System.out.println("The close_up process is completed"); } @AfterTest public void reportReady() { System.out.println("Report is ready to be shared, with screenshots of tests"); } @AfterSuite public void cleanUp() { System.out.println("All close up activities completed"); } @BeforeGroups("urlValidation") public void setUpSecurity() { System.out.println("url validation test starting"); } @AfterGroups("urlValidation") public void tearDownSecurity() { System.out.println("url validation test finished"); } }
Console Output:
TestNG Report:
Annotations In TestNG For Desired Purpose
There are more annotations than the ones defined above, which are used for desired purpose only.
@DataProvider
This annotated method is used for supplying data to the test method in which the dataProvider attribute is defined. This annotated method helps in creating a data driven framework where multiple sets of input values can be given which returns a 2D array or object. @DataProvider annotation in TestNG comes with two attributes.
- name- this attribute is used to provide name to the dataprovider. If not set it defaults to the name of the method provided.
- parallel-this is one attribute that helps in running your tests in parallel with different variation of data. This attribute is one of the reasons to make TestNG more powerful to Junit. Its default value is false.
Below is the code snippet indicating the use of @DataProvider annotation with name and parallel attribute set to it.
@DataProvider(name="SetEnvironment", parallel=true) public Object[][] getData(){ Object[][] browserProperty = new Object[][]{ {Platform.WIN8, "chrome", "70.0"}, {Platform.WIN8, "chrome", "71.0"} }; return browserProperty; }
@Factory
This annotation helps to run multiple test classes through a single test class. It basically defines and create tests dynamically.
The below code snippet indicates the use of @Factory annotation that helps calls the test method class.
package ChromeDriver; import org.testng.annotations.Test; public class FactorySimplyTest1 { @Test public void testMethod1() { System.out.println("This is to test for method 1 for Factor Annotation"); }} package ChromeDriver; import org.testng.annotations.Test; public class FactorySimpleTest2 { @Test public void testMethod2() { System.out.println("This is to test for method 2 for Factor Annotation"); } } package ChromeDriver; import org.testng.annotations.Factory; import org.testng.annotations.Test; public class FactoryAnnotation { @Factory() @Test public Object[] getTestFactoryMethod() { Object[] factoryTest = new Object[2]; factoryTest[0] = new FactorySimplyTest1(); factoryTest[1] = new FactorySimpleTest2(); return factoryTest; } }
Console Output:
@Parameters
This annotation helps you pass parameters to your tests directly via the testNG.xml file. Usually this is preferred when you have limited data sets to try on your tests. In case of complicated and large data sets @dataProvider annotation is preferred or excel.
The below code snippet showcase the same:
@Parameters({ "username", "password"}) @Test() public void checkLogin(String username, String password) { driver.get("https://accounts.lambdatest.com/login"); driver.findElement(By.xpath("//input[@name='email']")).sendKeys(username); driver.findElement(By.xpath("//input[@name='password']")).sendKeys(password); driver.findElement(By.xpath("//*[@id='app']/section/form/div/div/button")).click(); System.out.println("The login process on lamdatest is completed"); }
The parameter values are defined in the TestNG.xml file as below:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="Suite"> <test thread-count="5" name="Annotations"> <parameter name="username" value="sadhvisingh24@gmail.com" /> <parameter name="password" value="XXXXX" /> <classes> <class name="Parameter_annotation"/> </classes> </test> <!-- Annotations --> </suite> <!-- Suite -->
@Listener
This annotation helps in logging and reporting. We have multiple listeners like:
- IExecutionListener
- IAnnotationTransformer
- ISuiteListener
- ITestListener
But to go in depth with these listeners and their uses would be a talk for another blog. I will be writing one soon, so stay tuned.
That Was All!
The key point to note while working with all these annotations and attributes is your system should have java 1.5 version or higher as these annotations are not supported for all lower versions of java and you may tend to receive error for them.
All the above mentioned annotations and attributes of TestNG helps to provide better structuring and readability to the code. It helps provide detailed reports that makes status reporting part even easier and useful. Use of these annotations in TestNG for Selenium completely depend on your business requirements. Hence, choosing the right ones for the right use is important.Try out these annotations in TestNG on LambdaTest Selenium Grid now!
Published on Java Code Geeks with permission by Sadhvi Singh, partner at our JCG program. See the original article here: Complete Guide On TestNG Annotations For Selenium WebDriver Opinions expressed by Java Code Geeks contributors are their own. |