TestNG Annotations 101
This article explains basics of all TestNG annotations, provides examples for each annotation, explains each TestNG annotation in more detail along with its attributes, and provides tips and tricks for efficient usage.
A Brief Introduction to Annotations
Annotations are used to provide additional information (Metadata) about a program; To be specific it provides additional information about variables, methods or classes to compiler. It has following properties
- It always start with ‘@’ character
- They do not change the action of a compiled program
- Generally used to associate certain metadata (data about data) to instance variables, methods, classes, etc
- Annotations can change the way a program is treated by compiler; However it has no direct effect on the operation of the annotated code
Annotations have a many uses and few important among them are given below.
- Information for the compiler — Annotations can be used by the compiler to detect errors or suppress warnings.
- Compile-time and deployment-time processing — Software tools can process annotation information to generate code, XML files, and so forth.
- Runtime processing — Some annotations are available to be examined at runtime.
Basics of TestNG Suite
Basic understanding of TestNG test suite is necessary to understand the behavior of TestNG annotations. It is nothing but a xml file to group classes under test group and test groups under suite.
- There should be only one suite
- Suite can have ‘n’ number of test groups
- Each test group can have more than one class list
- Each class list is a list of classes; and can be one or more
For Example, consider below TestNG test suite.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="allselenium_example_suite"> <test name="allselenium_example_test_1"> <classes> <class name="allselenium.testng.AnnotationsDiffGroupClass"/> <class name="allselenium.testng.AnnotationsSameGroupClass"/> <class name="allselenium.testng.AnnotationsExampleClass"/> </classes> </test> <test name="allselenium_example_test_2"> <classes> <class name="allselenium.testng.AnnotationsDiffGroupClass"/> </classes> </test> </suite>
- There is only one suite – “allselenium_example_suite“
- There are two test groups – “allselenium_example_test_1” and “allselenium_example_test_2“
- Each class list have more than one class
We are going to use above suite to understand annotations more clearly. So it is ok to spend more time to understand this TestNG suite.
TestNG Annotations
TestNG use these annotations to help in making a robust test framework.
List of all TestNG Annotations
@BeforeSuite
@BeforeTest
@BeforeClass
@BeforeGroups
@BeforeMethod
@Test
@AfterMethod
@AfterGroups
@AfterClass
@AfterTest
@AfterSuite
@DataProvider
@Listener
@Parameters
@Factory
Test
Marks a class as a test – all methods inside the class without any other annotations marked are considered as test methods
@Test public class TestNGAnnotations() { public void validateMessageTest1() { Assert.assertTrue(true); } public void validateMessageTest2() { Assert.assertTrue(true); } }
Marks an individual method as a test
@Test public void validateMessageTest1() { Assert.assertTrue(true); }
BeforeSuite
Any method marked with this annotation will run only once before all tests in the test suite. If there are more than one BeforeSuite annotated methods, all will be executed.
@BeforeSuite public void beforeSuiteMethod() { System.out.println("BeforeSuite method"); }
AfterSuite
Any method marked with this annotation will run once after execution of all tests in the test suite. If there are more than one AfterSuite annotated methods, all will be executed.
@AfterSuite public void afterSuiteMethod() { System.out.println("AfterSuite method"); }
BeforeTest
Any method marked with this annotation will be executed before first @Test annotated method in the test group in test suite. Local to to the test group and runs only once for the test group in xml suite file.
@BeforeTest public void beforeTestMethod() { System.out.println("BeforeTest method - "+this.getClass().getSimpleName()); }
AfterTest
Any method marked with this annotation will be executed after all @Test annotated methods complete the execution in the test group in test suite. Local to to the test group and runs only once for the test group in xml suite file.
@AfterTest public void afterTestMethod() { System.out.println("AfterTest method - "+this.getClass().getSimpleName()); }
BeforeClass
Any method marked with this annotation will be executed before first @Test method execution in the class. Local to the class and runs only once for the class.
@BeforeClass public void beforeClassMethod() { System.out.println("BeforeClass method"); }
AfterClass
Any method marked with this annotation will be executed after all the test methods in the current class have been executed. Local to the class and runs only once for the class.
@AfterClass public void afterClassMethod() { System.out.println("AfterClass method"); }
BeforeGroups
Any method marked with this annotation will be executed before execution of any test in the specified group in all the class list in the test group.
@BeforeGroups("default") public void beforeGroupsMethod() { System.out.println("BeforeGroups method"); }
AfterGroups
Any method marked with this annotation will be executed after execution of all tests in the specified group in all the class list in the test group.
@AfterGroups("default") public void afterGroupsMethod() { System.out.println("AfterGroups method"); }
BeforeMethod
Any method marked with this annotation will be executed before every @Test annotated method in that class. Scope of this BeforeMethod is ‘class‘.
@BeforeMethod public void beforeMethodMethod() { System.out.println("BeforeMethod method"); }
AfterMethod
Any method marked with this annotation will be executed after every @Test annotated method in that class. Scope of this AfterMethod is ‘class‘.
@AfterMethod public void afterMethodMethod() { System.out.println("AfterMethod method"); }
Parameters
This annotation is used to pass parameters to test methods.
DataProvider
If we use @DataProvider annotation for any method that means you are using that method as a data supplier. The configuration of @DataProvider annotated method must be like it always return Object[][] which we can use in @Test annotated method. The @Test method that wants to receive data from this DataProvider needs to use a dataProvider name equals to the name of this annotation.
Factory
Marks a method as a factory that returns objects that will be used by TestNG as Test classes. The method must return Object[ ].
Listeners
This annotation is used with test class. It helps in writing logs and results.
Benefits of using TestNG Annotations
- It identifies the methods it is interested in by looking up annotations. Hence method names are not restricted to any pattern or format.
- We can pass additional parameters to annotations.
- Annotations are strongly typed, so the compiler will flag any mistakes right away.
- Test classes no longer need to extend anything (such as Test Case, for JUnit 3).
TestNG Annotations order of Execution
Inside same class
Example Class – AnnotationsExample.java
import org.testng.Assert; 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 AnnotationsExample { @BeforeSuite public void beforeSuiteMethod() { System.out.println("BeforeSuite method - "+this.getClass().getSimpleName()); } @BeforeTest public void beforeTestMethod() { System.out.println("BeforeTest method - "+this.getClass().getSimpleName()); } @BeforeClass public void beforeClassMethod() { System.out.println("BeforeClass method - "+this.getClass().getSimpleName()); } @BeforeGroups("default") public void beforeGroupsMethod() { System.out.println("BeforeGroups method - "+this.getClass().getSimpleName()); } @BeforeMethod public void beforeMethodMethod() { System.out.println("BeforeMethod method - "+this.getClass().getSimpleName()); } @Test(groups={"default"}) public void validateMessageTest1() { System.out.println("Test 1 validation in progress - "+this.getClass().getSimpleName()); Assert.assertTrue(true); } @Test(groups={"default"}) public void validateMessageTest2() { System.out.println("Test 2 validation in progress - "+this.getClass().getSimpleName()); Assert.assertTrue(true); } @AfterMethod public void afterMethodMethod() { System.out.println("AfterMethod method - "+this.getClass().getSimpleName()); } @AfterGroups("default") public void afterGroupsMethod() { System.out.println("AfterGroups method - "+this.getClass().getSimpleName()); } @AfterClass public void afterClassMethod() { System.out.println("AfterClass method - "+this.getClass().getSimpleName()); } @AfterTest public void afterTestMethod() { System.out.println("AfterTest method - "+this.getClass().getSimpleName()); } @AfterSuite public void afterSuiteMethod() { System.out.println("AfterSuite method - "+this.getClass().getSimpleName()); } }
TestNG Suite
<?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="Test"> <classes> <class name="ar.learn.testng.AnnotationsExample"/> </classes> </test> </suite>
Output
[RemoteTestNG] detected TestNG version 6.14.2 BeforeSuite method - AnnotationsExample BeforeTest method - AnnotationsExample BeforeClass method - AnnotationsExample BeforeGroups method - AnnotationsExample BeforeMethod method - AnnotationsExample Test 1 validation in progress - AnnotationsExample AfterMethod method - AnnotationsExample BeforeMethod method - AnnotationsExample Test 2 validation in progress - AnnotationsExample AfterMethod method - AnnotationsExample AfterGroups method - AnnotationsExample AfterClass method - AnnotationsExample AfterTest method - AnnotationsExample AfterSuite method - AnnotationsExample
Multiple classes
AnnotationsExample.java
import org.testng.Assert; 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 AnnotationsExample { @BeforeSuite public void beforeSuiteMethod() { System.out.println("BeforeSuite method - "+this.getClass().getSimpleName()); } @BeforeTest public void beforeTestMethod() { System.out.println("BeforeTest method - "+this.getClass().getSimpleName()); } @BeforeClass public void beforeClassMethod() { System.out.println("BeforeClass method - "+this.getClass().getSimpleName()); } @BeforeGroups("default") public void beforeGroupsMethod() { System.out.println("BeforeGroups method - "+this.getClass().getSimpleName()); } @BeforeMethod public void beforeMethodMethod() { System.out.println("BeforeMethod method - "+this.getClass().getSimpleName()); } @Test(groups={"default"}) public void validateMessageTest1() { System.out.println("Test 1 validation in progress - "+this.getClass().getSimpleName()); Assert.assertTrue(true); } @Test(groups={"default"}) public void validateMessageTest2() { System.out.println("Test 2 validation in progress - "+this.getClass().getSimpleName()); Assert.assertTrue(true); } @AfterMethod public void afterMethodMethod() { System.out.println("AfterMethod method - "+this.getClass().getSimpleName()); } @AfterGroups("default") public void afterGroupsMethod() { System.out.println("AfterGroups method - "+this.getClass().getSimpleName()); } @AfterClass public void afterClassMethod() { System.out.println("AfterClass method - "+this.getClass().getSimpleName()); } @AfterTest public void afterTestMethod() { System.out.println("AfterTest method - "+this.getClass().getSimpleName()); } @AfterSuite public void afterSuiteMethod() { System.out.println("AfterSuite method - "+this.getClass().getSimpleName()); } }
AnnotationsSameGroup.java
import org.testng.Assert; import org.testng.annotations.Test; public class AnnotationsSameGroup { @Test(groups={"default"}) public void validatePrint() { System.out.println("Validation in progress "+this.getClass().getSimpleName()); Assert.assertTrue(true); } }
AnnotationsDifferentGroup.java
import org.testng.Assert; import org.testng.annotations.Test; public class AnnotationsDifferentGroup { @Test(groups={"special"}) public void validatePrint() { System.out.println("Validation in progress "+this.getClass().getSimpleName()); Assert.assertTrue(true); } }
TestNG Suite
<?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="Test"> <classes> <class name="ar.learn.testng.AnnotationsDifferentGroup"/> <class name="ar.learn.testng.AnnotationsSameGroup"/> <class name="ar.learn.testng.AnnotationsExample"/> </classes> </test> </suite>
Output
[RemoteTestNG] detected TestNG version 6.14.2 BeforeSuite method - AnnotationsExample BeforeTest method - AnnotationsExample Validation in progress AnnotationsDifferentGroup BeforeGroups method - AnnotationsExample Validation in progress AnnotationsSameGroup BeforeClass method - AnnotationsExample BeforeMethod method - AnnotationsExample Test 1 validation in progress - AnnotationsExample AfterMethod method - AnnotationsExample BeforeMethod method - AnnotationsExample Test 2 validation in progress - AnnotationsExample AfterMethod method - AnnotationsExample AfterGroups method - AnnotationsExample AfterClass method - AnnotationsExample AfterTest method - AnnotationsExample AfterSuite method - AnnotationsExample