Guide to TestNG in Java

Introduction

TestNG is a testing framework inspired by JUnit and NUnit but introduces new functionalities that make it more powerful and easier to use. It supports test configurations, parallel execution, dependency testing, data-driven testing, and more. This guide will cover the installation, basic usage, advanced features, and complex examples using TestNG.

Installation

To use TestNG, add the following dependency to your pom.xml if you're using Maven:

<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>7.7.0</version> <!-- or the latest version -->
    <scope>test</scope>
</dependency>

For Gradle:

dependencies {
    testImplementation 'org.testng:testng:7.7.0' // or the latest version
}

Basic Usage

Setting Up a Test Class

To create a TestNG test class, annotate methods with @Test.

Example

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

public class BasicTest {
    @Test
    public void testSum() {
        int a = 5;
        int b = 10;
        int sum = a + b;
        Assert.assertEquals(sum, 15, "Sum should be 15");
    }

    @Test
    public void testSubtraction() {
        int a = 10;
        int b = 5;
        int difference = a - b;
        Assert.assertEquals(difference, 5, "Difference should be 5");
    }
}

Running the Tests

To run the tests, you can use your IDE or the command line. In Maven, use:

mvn test

Output

[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running BasicTest
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.013 s - in BasicTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] -------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] -------------------------------------------------------
[INFO] Total time:  1.234 s
[INFO] Finished at: 2024-05-17T12:00:00
[INFO] -------------------------------------------------------

Advanced Features

Test Configuration

TestNG allows you to configure methods that run before and after test methods, classes, and suites using annotations like @BeforeMethod, @AfterMethod, @BeforeClass, @AfterClass, @BeforeSuite, and @AfterSuite.

Example

import org.testng.annotations.BeforeClass;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;

public class ConfigurationTest {
    @BeforeClass
    public void beforeClass() {
        System.out.println("Before Class");
    }

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

    @BeforeMethod
    public void beforeMethod() {
        System.out.println("Before Method");
    }

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

    @Test
    public void testMethod1() {
        System.out.println("Test Method 1");
    }

    @Test
    public void testMethod2() {
        System.out.println("Test Method 2");
    }
}

Output

Before Class
Before Method
Test Method 1
After Method
Before Method
Test Method 2
After Method
After Class

Parameterized Tests

TestNG supports parameterized tests using @Parameters and @DataProvider.

Example: @Parameters

First, configure parameters in testng.xml:

<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Suite">
    <test name="Test">
        <parameter name="username" value="Ravi" />
        <parameter name="age" value="25" />
        <classes>
            <class name="ParameterizedTest" />
        </classes>
    </test>
</suite>

Then, use the parameters in your test class:

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

public class ParameterizedTest {
    @Test
    @Parameters({"username", "age"})
    public void testParameters(String username, int age) {
        System.out.println("Username: " + username);
        System.out.println("Age: " + age);
        Assert.assertEquals(username, "Ravi");
        Assert.assertEquals(age, 25);
    }
}

Output

Username: Ravi
Age: 25

Example: @DataProvider

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

public class DataProviderTest {
    @DataProvider(name = "userData")
    public Object[][] userDataProvider() {
        return new Object[][] {
            {"Sita", 20},
            {"Lakshman", 30},
            {"Ram", 40}
        };
    }

    @Test(dataProvider = "userData")
    public void testDataProvider(String name, int age) {
        System.out.println("Name: " + name + ", Age: " + age);
        Assert.assertNotNull(name);
        Assert.assertTrue(age > 0);
    }
}

Output

Name: Sita, Age: 20
Name: Lakshman, Age: 30
Name: Ram, Age: 40

Dependency Testing

TestNG allows you to create dependent tests using the dependsOnMethods and dependsOnGroups attributes.

Example

import org.testng.annotations.Test;

public class DependencyTest {
    @Test
    public void init() {
        System.out.println("Init");
    }

    @Test(dependsOnMethods = "init")
    public void testMethod() {
        System.out.println("Test Method");
    }
}

Output

Init
Test Method

Grouping Tests

You can group tests into logical groups and run them together.

Example

import org.testng.annotations.Test;

public class GroupTest {
    @Test(groups = "sanity")
    public void testMethod1() {
        System.out.println("Sanity Test Method 1");
    }

    @Test(groups = "sanity")
    public void testMethod2() {
        System.out.println("Sanity Test Method 2");
    }

    @Test(groups = "regression")
    public void testMethod3() {
        System.out.println("Regression Test Method 1");
    }
}

Running Groups in testng.xml

<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Suite">
    <test name="Test">
        <groups>
            <run>
                <include name="sanity" />
            </run>
        </groups>
        <classes>
            <class name="GroupTest" />
        </classes>
    </test>
</suite>

Output

Sanity Test Method 1
Sanity Test Method 2

Parallel Execution

TestNG supports running tests in parallel, which can significantly reduce the execution time.

Example

<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Suite" parallel="methods" thread-count="3">
    <test name="Test">
        <classes>
            <class name="ParallelTest" />
        </classes>
    </test>
</suite>
import org.testng.annotations.Test;

public class ParallelTest {
    @Test
    public void testMethod1() {
        System.out.println("Test Method 1 - " + Thread.currentThread().getId());
    }

    @Test
    public void testMethod2() {
        System.out.println("Test Method 2 - " + Thread.currentThread().getId());
    }

    @Test
    public void testMethod3() {
        System.out.println("Test Method 3 - " + Thread.currentThread().getId());
    }
}

Output

Test Method 1 - 11
Test Method 2 - 12
Test Method 3 - 13

Complex Examples

Example: End-to-End Test Scenario

Let's consider a more complex example where we have to test a login feature of an application.

Example

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

public class LoginTest {
    @DataProvider(name = "loginData")
    public Object[][] loginDataProvider() {
        return new Object[][] {
            {"Ravi", "password123", true},
            {"Lakshmi", "wrongpassword", false},
            {"Arjun", "password456", true},
            {"Meera", "password789", false}
        };
    }

    @Test(dataProvider = "loginData")
    public void testLogin(String username, String password, boolean expectedResult) {
        boolean result = login(username, password);
        System.out.println("Username: " + username + ", Password: " + password + ", Expected Result: " + expectedResult + ", Actual Result

: " + result);
        Assert.assertEquals(result, expectedResult);
    }

    public boolean login(String username, String password) {
        // Simulate login logic
        if ("Ravi".equals(username) && "password123".equals(password)) {
            return true;
        } else if ("Arjun".equals(username) && "password456".equals(password)) {
            return true;
        } else {
            return false;
        }
    }
}

Output

Username: Ravi, Password: password123, Expected Result: true, Actual Result: true
Username: Lakshmi, Password: wrongpassword, Expected Result: false, Actual Result: false
Username: Arjun, Password: password456, Expected Result: true, Actual Result: true
Username: Meera, Password: password789, Expected Result: false, Actual Result: false

Example: API Testing

TestNG can also be used to test REST APIs. Here is an example using the RestAssured library.

Add RestAssured Dependency

<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>rest-assured</artifactId>
    <version>5.1.1</version> <!-- or the latest version -->
</dependency>

Example

import io.restassured.RestAssured;
import io.restassured.response.Response;
import org.testng.Assert;
import org.testng.annotations.Test;

public class ApiTest {
    @Test
    public void testGetUser() {
        Response response = RestAssured.get("https://jsonplaceholder.typicode.com/users/1");
        System.out.println("Response: " + response.asString());
        Assert.assertEquals(response.getStatusCode(), 200);
    }

    @Test
    public void testCreateUser() {
        String requestBody = "{ \"name\": \"Raj\", \"username\": \"rajkumar\", \"email\": \"raj@example.com\" }";

        Response response = RestAssured.given()
                .header("Content-Type", "application/json")
                .body(requestBody)
                .post("https://jsonplaceholder.typicode.com/users");

        System.out.println("Response: " + response.asString());
        Assert.assertEquals(response.getStatusCode(), 201);
    }
}

Output

Response: {user data...}
Response: {created user data...}

Conclusion

TestNG is a powerful and flexible testing framework for Java that supports various testing needs, including unit tests, integration tests, end-to-end tests, and API tests. This tutorial covered the basics of TestNG, including creating test classes, running tests, parameterized tests, dependency testing, grouping, and parallel execution. Additionally, we explored more complex examples like end-to-end testing scenarios and API testing. 

By leveraging TestNG, you can enhance your testing capabilities and ensure the quality and reliability of your Java applications. For more detailed information and advanced features, refer to the official TestNG documentation.

Comments