Getting started with TestNG

TestNG is a testing framework inspired by JUnit but introducing a whole set of new functionalities. In this tutorial we will walk through the set up and execution of some example tests with TestNG.

What is TestNG?

TestNG is an open source automated testing framework. It has been designed to reduce some of the limitations of JUnit to make it more flexible and powerful. The highlights of TestNG are:

  • TestNG supports a wide range of annotations.
  • TestNG uses more Java and OO features.
  • TestNG supports testing integrated classes (i.e. by default, no need to create a new test class instance for every test method).
  • TestNG has a clean separation from compile-time test code and run-time configuration/data info.
  • TestNG supports a flexible runtime configuration.
  • TestNG introduces the concept of ‘test groups’. Once you have compiled your tests, you can just ask TestNG to run all the “front-end” tests, or “fast”, “slow”, “database” tests, etc.
  • TestNG supports Dependent test methods, parallel testing, load testing, and partial failure.
  • TestNG has a flexible plug-in API.
  • TestNG has support for multi threaded testing.

Setting up Test NG

Let’s write a proof of concept Hello World example with TestNG.

Firstly, we will add to our pom.xml the latest version of Test NG which as of May 2024 it’s the version 7.10.2:

<dependency>
   <groupId>org.testng</groupId>
   <artifactId>testng</artifactId>
   <version>7.10.2</version>
   <scope>test</scope>
</dependency>

On the other hand, if you are using Gradle, you will need the following basic configuration in your build.gradle file:

test { //this is the gradle task to be executed
  useTestNG() { //Tells Gradle to use TestNG
       useDefaultListeners = true // Tells TestNG to execute its default reporting structure
       suites 'src/test/suite.xml' //location of our suite.xml
  }
}

Running TestNG on Eclipse

You can run your Test classes from the Command Line or from your IDE. For example, to run TestNG suites from Eclipse you can install its plug-in which is available in the Eclipse Marketplace:

testng tutorial

Choose Install and restart Eclipse.

Coding your first TestNG Class

Here is your example App.java file:

public class App {
    
    public int sum(int a, int b) {
        return a + b;
    }
}

Now let’s test it with TestNG:

import org.testng.Assert;
import org.testng.annotations.Test;

public class AppTest 
{
    @Test
    public void helloworld() {
        App a = new App(); 
        Assert.assertEquals(10, a.sum(5,5));
    }

}

if you have installed Eclipse TestNG plugin, you can simply run the Test by right-clicking on the Class and choosing Run As | TestNG Test. Otherwise, from the command line, run the Maven test goal:

$ mvn test

Next, check the output:

PASSED: helloworld

===============================================
    Default test
    Tests run: 1, Failures: 0, Skips: 0
================================================

TestNG annotations order

Much alike JUnit, you can capture Test lifecycle steps using annotations. the Following Test class shows how to intercept the various phases of a TestNG Class:

import org.testng.annotations.Test;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.AfterSuite;

public class SampleTestNGClass {
    
  @Test
  public void hello() {
      System.out.println("@Test annotation");
  }
  
  @BeforeMethod
  public void beforeMethod() {
      System.out.println("@BeforeMethod annotation");
  }

  @AfterMethod
  public void afterMethod() {
      System.out.println("@AfterMethod annotation");
  }

  @BeforeClass
  public void beforeClass() {
      System.out.println("@BeforeClass annotation");
  }

  @AfterClass
  public void afterClass() {
      System.out.println("@AfterClass annotation");
  }

  @BeforeTest
  public void beforeTest() {
      System.out.println("@BeforeTest annotation");
  }

  @AfterTest
  public void afterTest() {
      System.out.println("@AfterTest annotation");
  }

  @BeforeSuite
  public void beforeSuite() {
      System.out.println("@BeforeSuite annotation");
  }

  @AfterSuite
  public void afterSuite() {
      System.out.println("@AfterSuite annotation");
  }

}

And here is the execution order for all the above methods:

  • BeforeSuite and AfterSuite methods are executed only once.
  • BeforeTest and AfterTest methods are executed only once per test class.
  • BeforeClass and AfterClass methods are executed only once per class.
  • BeforeMethod and AfterMethod methods are executed for all @Test methods.
  • If the TestNG class contains more than one methods marked with @BeforeMethod and @AfterMethod, then all the methods are executed before and after every @Test method.

A common question is about the difference between BeforeTest and BeforeMethod. We can summarize it as follows:

  • @BeforeTest : It will call only once, before Test method.
  • @BeforeMethod It will call every time before Test Method.

When should you use BeforeSuite?

@BeforeSuite is typically used when we have different environment vars to run your test cases. You can set them in a @BeforeSuite annotated method so that before executing all the test cases, you need to load all the environment variables for your framework, and then it starts executing your test cases.

Running the same Test with multiple parameters

One of the most interesting features of TestNG is the ability to run multiple times the same test using a different set of parameters. You can achieve that by defining a method as @DataProvider and having it to return a set of parameters.

See the following example:

import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class DataProviderTest {

    @Test(dataProvider = "provideNumbers")
    public void test(int number, int expected) {
        Assert.assertEquals(number + 10, expected);
    }

    @DataProvider(name = "provideNumbers")
    public Object[][] provideData() {

        return new Object[][] { 
            { 10, 20 }, 
            { 100, 110 }, 
            { 200, 210 }, 
            { 300, 310 }, 
            { 400, 210 } 
        };
    }

}

The above example runs 5 executions of the same test method, each one with a different couple of parameters.