TestNG is an automated testing framework. In this tutorial, let us explore more about how it can be used in a software lifecycle.
Unit Testing
Instead of testing the whole program, testing the code at the class level, method level, etc., is called Unit Testing The code has to be split into separate classes and methods so that testing can be carried out easily at a unit level.
Integration Testing
After the completion of Unit testing, there will always be the necessity for integration testing. Several units are tested in groups and this will help to reduce the defects exposed at the time of integration of several modules.
Example: We can run tests together by means of specifying “suite name” and can do different classes together.
Priority Testing
By using annotations like @Test(priority=1/2/…), we can set the priority of the tests. If a test class is having @Test annotation alone, it will high priority and if any specific test numbers are given, it is executed as per the order. So we can set the order of execution by using annotations as above. Let us take a maven project and from there will cover important topics.
Example Project
Project Structure:
This is a maven kind of project and hence dependencies need to be mentioned in
pom.xml
XML
<? xml version = "1.0" encoding = "UTF-8" ?> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 < modelVersion >4.0.0</ modelVersion > < groupId >com.gfg.testng</ groupId > < artifactId >testng</ artifactId > < version >0.1.0-SNAPSHOT</ version > < name >testng</ name > < packaging >jar</ packaging > < dependencies > <!-- This is the essential dependency required for testng --> < dependency > < groupId >org.testng</ groupId > < artifactId >testng</ artifactId > < version >${testng.version}</ version > < scope >test</ scope > </ dependency > <!-- As we are logging, below dependency is required --> < dependency > < groupId >org.slf4j</ groupId > < artifactId >slf4j-api</ artifactId > < version >1.7.9</ version > </ dependency > </ dependencies > < build > < finalName >testng</ finalName > < resources > < resource > < directory >src/main/resources</ directory > < filtering >true</ filtering > </ resource > </ resources > < testResources > < testResource > < directory >src/main/resources</ directory > < filtering >true</ filtering > </ testResource > </ testResources > </ build > < profiles > < profile > < id >default-second</ id > < build > < plugins > < plugin > < groupId >org.apache.maven.plugins</ groupId > < artifactId >maven-surefire-plugin</ artifactId > < configuration > < suiteXmlFiles > < suiteXmlFile >src\test\resources\parametrized_testng.xml</ suiteXmlFile > </ suiteXmlFiles > </ configuration > </ plugin > </ plugins > </ build > </ profile > < profile > < id >integration-lite-second</ id > < build > < plugins > < plugin > < groupId >org.apache.maven.plugins</ groupId > < artifactId >maven-surefire-plugin</ artifactId > < configuration > < suiteXmlFiles > < suiteXmlFile >src\test\resources\test_int.xml</ suiteXmlFile > </ suiteXmlFiles > </ configuration > </ plugin > </ plugins > </ build > </ profile > </ profiles > < properties > < testng.version >7.1.0</ testng.version > < project.build.sourceEncoding >UTF-8</ project.build.sourceEncoding > < maven.compiler.source >1.8</ maven.compiler.source > < maven.compiler.target >1.8</ maven.compiler.target > </ properties > </ project > |
In TestNG, Via XML files, We can pass parameters as specified in the below XML using <parameter> tag with name and value
XML
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > < suite name = "My test suite" > < listeners > < listener class-name = "com.gfg.reports.CustomisedListener" ></ listener > </ listeners > < test name = "numbersXML" > <!-- We can specify as much parameters and their values here --> < parameter name = "value" value = "1" /> < parameter name = "isEven" value = "false" /> < classes > < class name = "com.gfg.ParametrizedUnitTest" /> </ classes > </ test > </ suite > |
These parameters are collected via @DataProvider or @Parameter in Java files
@DataProvider(name = "numbers") public static Object[][] evenNumbers() { return new Object[][]{{11, false}, {2222, true}, {4882, true}}; }
We can run tests together by means of specifying “suite name” and can do different classes together.
XML
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > < suite name = "int" > < test name = "integration tests" > < classes > < class name = "com.gfg.MultiThreadedIntegrationTest" /> < class name = "com.gfg.TimeOutCheckTest" /> </ classes > </ test > </ suite > |
This specifies that “int” is the suite name and 2 classes namely com.gfg.MultiThreadedIntegrationTest and com.gfg.TimeOutCheckTest together. Like this, we can group classes under a single suite. And also we can specify different suite names and can group classes whichever we need. Dependency tests. i.e. depends upon a specific test and thereupon logging some information
Usecase: Check whether an email is valid or not and if valid, proceed to the next set of steps
private String userEmail = "geek@gfg.com"; @Test public void checkForValidMail() { boolean validEmail = userEmail.contains("@"); Assert.assertEquals(validEmail, true); } // If first test is success, below test executes and logs the information @Test(dependsOnMethods = {"checkForValidMail"}) public void logInWhenEmailValid() { LOGGER.info("Given Email {} valid >> and logging in", userEmail); }
Order of test execution can be controlled by using @Priority annotation
@Test(priority = 1) // This is executed first public void stringToIntCheck() { String testString = "100"; assertTrue(Integer.valueOf(testString) instanceof Integer); } @Test(priority = 2) // This is second public void intToStringCheck() { int testInt = 100; assertTrue(String.valueOf(testInt) instanceof String); }
Test Timeout can be mentioned by using @Test(timeout=<certain value>). TestNG supports for timed out tests.
@Test(timeOut = 1000, enabled = false) public void asNoStoppingPointItRunsTimeOut() { while (true) ; }
- Actually, in the previous test, we are having enabled = false,, that is if we want to ignore the test cases
- We can include
- @BeforeClass and @AfterClass at the class level are mainly used to initialize and clean up the code.
- Similarly, we can include @BeforeMethod and @AfterMethod at the method level
- @BeforeSuite, @AfterSuite, @BeforeGroup, and @AfterGroup annotations, for configurations at suite and group levels respectively.
private int evenNumber, oddNumber; @BeforeClass public void setup() { evenNumber = 100; oddNumber = 59; } @AfterClass public void tearDown() { evenNumber = 0; oddNumber = 0; }
As a whole let us see the java code with the above features
DependencyUnitTest.java
Java
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.Assert; import org.testng.annotations.Test; public class DependencyUnitTest { private static final Logger LOGGER = LoggerFactory.getLogger(DependencyUnitTest. class ); private String userEmail = "geek@gfg.com" ; @Test public void checkForValidMail() { boolean validEmail = userEmail.contains( "@" ); Assert.assertEquals(validEmail, true ); } @Test (dependsOnMethods = { "checkForValidMail" }) public void logInWhenEmailValid() { LOGGER.info( "Given Email {} valid >> and logging in" , userEmail); } } |
MultiThreadedIntegrationTest.java
Java
import org.testng.Assert; import org.testng.annotations.Test; public class MultiThreadedIntegrationTest { @Test (threadPoolSize = 5 , invocationCount = 10 , timeOut = 1000 ) public void checkForCount() { int count = Thread.activeCount(); Assert.assertTrue(count > 2 ); } } |
OddOrEvenNumberCheck.java
Java
import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class OddOrEvenNumberCheck extends TestNG { private int evenNumber, oddNumber; @BeforeClass public void setup() { evenNumber = 100 ; oddNumber = 59 ; } @AfterClass public void tearDown() { evenNumber = 0 ; oddNumber = 0 ; } @Test public void checkEven() { Assert.assertTrue(evenNumber % 2 == 0 ); } @Test public void checkOdd() { Assert.assertTrue(oddNumber % 2 == 1 ); } } |
ParametrizedUnitTest.java
Java
import org.testng.annotations.DataProvider; import org.testng.annotations.Parameters; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; public class ParametrizedUnitTest { @DataProvider (name = "numbers" ) public static Object[][] evenNumbers() { return new Object[][]{{ 11 , false }, { 2222 , true }, { 4882 , true }}; } @Test (dataProvider = "numbers" ) public void evenNumberCheck(Integer number, boolean expected) { assertEquals(expected, number % 2 == 0 ); } @Test (dataProvider = "numbersObject" ) public void evenNumberObjectCheck(EvenNumberPOJO number) { assertEquals(number.isEven(), number.getValue() % 2 == 0 ); } @DataProvider (name = "numbersObject" ) public Object[][] parameterProvider() { return new Object[][]{{ new EvenNumberPOJO( 111 , false )}, { new EvenNumberPOJO( 2432 , true )}, { new EvenNumberPOJO( 4712 , true ),}}; } class EvenNumberPOJO { private int value; private boolean isEven; EvenNumberPOJO( int number, boolean isEven) { this .value = number; this .isEven = isEven; } int getValue() { return value; } public void setValue( int value) { this .value = value; } boolean isEven() { return isEven; } public void setEven( boolean even) { isEven = even; } @Override public String toString() { return "EvenNumber{" + "value=" + value + ", isEven=" + isEven + '}' ; } } } |
PriorityUnitTest.java
Java
import org.testng.annotations.Test; import static org.testng.Assert.assertTrue; public class PriorityUnitTest { @Test (priority = 1 ) public void stringToIntCheck() { String testString = "100" ; assertTrue(Integer.valueOf(testString) instanceof Integer); } @Test (priority = 2 ) public void intToStringCheck() { int testInt = 100 ; assertTrue(String.valueOf(testInt) instanceof String); } } |
TimeOutCheckTest.java
Java
import org.testng.annotations.Test; public class TimeOutCheckTest { // @Test(timeOut = 1000) // If we want to skip the test means, // enabled = false has to be added @Test (timeOut = 1000 , enabled = false ) public void asNoStoppingPointItRunsTimeOut() { while ( true ) ; } } |
Now let’s run the test by using
mvn test
Or from eclipse
Output:
We can see the success/failure reports under the target/surefire-reports folder as well.