Basic Assertions
Assertions are the foundation of test validation in TestNG. They allow you to verify that your code behaves as expected by comparing actual results with expected values. TestNG provides a rich set of assertion methods through the org.testng.Assert class.
assertEquals
The most commonly used assertion is assertEquals, which verifies that two values are equal:
import org.testng.Assert;
import org.testng.annotations.Test;
public class EqualsAssertionExample {
@Test
public void testStringEquality() {
String actual = "TestNG";
String expected = "TestNG";
Assert.assertEquals(actual, expected, "Strings should be equal");
}
@Test
public void testNumericEquality() {
int actual = 5 + 3;
int expected = 8;
Assert.assertEquals(actual, expected, "Addition result should be 8");
}
@Test
public void testDoubleEquality() {
double actual = 5.01;
double expected = 5.0;
double delta = 0.1; // Acceptable difference
Assert.assertEquals(actual, expected, delta, "Doubles should be equal within delta");
}
}
assertNotEquals
This assertion verifies that two values are not equal:
import org.testng.Assert;
import org.testng.annotations.Test;
public class NotEqualsAssertionExample {
@Test
public void testStringInequality() {
String actual = "TestNG";
String expected = "JUnit";
Assert.assertNotEquals(actual, expected, "Strings should not be equal");
}
@Test
public void testNumericInequality() {
int actual = 5 + 3;
int expected = 9;
Assert.assertNotEquals(actual, expected, "Addition result should not be 9");
}
}
assertTrue and assertFalse
These assertions verify boolean conditions:
import org.testng.Assert;
import org.testng.annotations.Test;
public class BooleanAssertionExample {
@Test
public void testTrueCondition() {
boolean condition = 5 > 3;
Assert.assertTrue(condition, "5 should be greater than 3");
}
@Test
public void testFalseCondition() {
boolean condition = 5 < 3;
Assert.assertFalse(condition, "5 should not be less than 3");
}
@Test
public void testStringContains() {
String text = "TestNG is a testing framework";
Assert.assertTrue(text.contains("TestNG"), "Text should contain 'TestNG'");
Assert.assertFalse(text.contains("JUnit"), "Text should not contain 'JUnit'");
}
}
assertNull and assertNotNull
These assertions verify that an object is null or not null:
import org.testng.Assert;
import org.testng.annotations.Test;
public class NullAssertionExample {
@Test
public void testNullObject() {
Object obj = null;
Assert.assertNull(obj, "Object should be null");
}
@Test
public void testNotNullObject() {
Object obj = new Object();
Assert.assertNotNull(obj, "Object should not be null");
}
@Test
public void testMethodReturningNull() {
String result = getValueFromDatabase("nonexistent");
Assert.assertNull(result, "Result should be null for nonexistent key");
}
private String getValueFromDatabase(String key) {
// Simulate database lookup
if ("nonexistent".equals(key)) {
return null;
}
return "some value";
}
}
assertSame and assertNotSame
These assertions verify object identity (reference equality) rather than value equality:
import org.testng.Assert;
import org.testng.annotations.Test;
public class SameAssertionExample {
@Test
public void testSameObject() {
Object obj1 = new Object();
Object obj2 = obj1; // Same reference
Assert.assertSame(obj1, obj2, "Objects should be the same instance");
}
@Test
public void testNotSameObject() {
Object obj1 = new Object();
Object obj2 = new Object(); // Different reference
Assert.assertNotSame(obj1, obj2, "Objects should be different instances");
}
@Test
public void testStringIntern() {
String s1 = "TestNG"; // String literal, goes to string pool
String s2 = new String("TestNG").intern(); // Explicitly interned
Assert.assertSame(s1, s2, "Interned strings should be the same instance");
}
}
Advanced Assertions
TestNG provides more advanced assertion capabilities for complex validation scenarios.
assertEqualsNoOrder
This assertion verifies that two arrays contain the same elements, regardless of their order:
import org.testng.Assert;
import org.testng.annotations.Test;
public class ArrayAssertionExample {
@Test
public void testArrayEquality() {
String[] actual = {"TestNG", "JUnit", "Mockito"};
String[] expected = {"JUnit", "TestNG", "Mockito"};
// This would fail with assertEquals
// Assert.assertEquals(actual, expected, "Arrays should be equal");
// This passes because order doesn't matter
Assert.assertEqualsNoOrder(actual, expected, "Arrays should contain the same elements");
}
}
assertThrows
This assertion verifies that a specific exception is thrown:
import org.testng.Assert;
import org.testng.annotations.Test;
public class ExceptionAssertionExample {
@Test
public void testExceptionThrown() {
Assert.assertThrows(ArithmeticException.class, () -> {
int result = 1 / 0; // This should throw ArithmeticException
});
}
@Test
public void testExceptionWithMessage() {
ArithmeticException exception = Assert.expectThrows(ArithmeticException.class, () -> {
int result = 1 / 0;
});
Assert.assertEquals(exception.getMessage(), "/ by zero", "Exception message should match");
}
}
Collection Assertions
TestNG doesn't have built-in collection assertions, but you can use Java's collection methods with standard assertions:
import org.testng.Assert;
import org.testng.annotations.Test;
import java.util.Arrays;
import java.util.List;
public class CollectionAssertionExample {
@Test
public void testListContents() {
List<String> actual = Arrays.asList("TestNG", "JUnit", "Mockito");
// Check size
Assert.assertEquals(actual.size(), 3, "List should contain 3 elements");
// Check specific element
Assert.assertEquals(actual.get(0), "TestNG", "First element should be TestNG");
// Check if list contains element
Assert.assertTrue(actual.contains("Mockito"), "List should contain Mockito");
// Check if list contains all elements
List<String> expected = Arrays.asList("TestNG", "Mockito");
Assert.assertTrue(actual.containsAll(expected), "List should contain all expected elements");
}
}
Soft Assertions
Standard assertions in TestNG stop test execution when an assertion fails. Soft assertions allow multiple assertions to be collected before reporting failures, which is useful when you want to check multiple conditions in a single test.
Using SoftAssert
import org.testng.annotations.Test;
import org.testng.asserts.SoftAssert;
public class SoftAssertExample {
@Test
public void testMultipleConditions() {
SoftAssert softAssert = new SoftAssert();
// These assertions will not stop execution if they fail
softAssert.assertEquals(5 + 3, 8, "Addition should work");
softAssert.assertEquals(5 - 3, 2, "Subtraction should work");
softAssert.assertEquals(5 * 3, 15, "Multiplication should work");
softAssert.assertEquals(6 / 3, 2, "Division should work");
// This assertion will fail but execution continues
softAssert.assertEquals(5 / 2, 3, "Integer division should work");
// More assertions
softAssert.assertTrue(5 > 3, "5 should be greater than 3");
// This is required to throw an exception if any assertions failed
softAssert.assertAll();
}
}
Custom Soft Assert Implementation
You can create a custom soft assertion class to add domain-specific assertions:
import org.testng.asserts.SoftAssert;
public class CustomSoftAssert extends SoftAssert {
public void assertPositive(int value, String message) {
if (value <= 0) {
failWithMessage(message + ": expected positive but was " + value);
}
}
public void assertInRange(int value, int min, int max, String message) {
if (value < min || value > max) {
failWithMessage(message + ": expected in range [" + min + ", " + max + "] but was " + value);
}
}
private void failWithMessage(String message) {
try {
fail(message);
} catch (AssertionError e) {
// SoftAssert will collect this exception
throw e;
}
}
}
Usage example:
import org.testng.annotations.Test;
public class CustomSoftAssertExample {
@Test
public void testCustomAssertions() {
CustomSoftAssert softAssert = new CustomSoftAssert();
softAssert.assertPositive(5, "Value should be positive");
softAssert.assertPositive(-1, "This will fail but continue");
softAssert.assertInRange(7, 1, 10, "Value should be in range");
softAssert.assertInRange(15, 1, 10, "This will also fail but continue");
softAssert.assertAll(); // Reports all failures
}
}
Custom Assertions with Java 21
Java 21 features can enhance your assertion capabilities. Let's explore some examples:
Record Pattern Assertions
Using Java 21's record patterns for more expressive assertions:
import org.testng.Assert;
import org.testng.annotations.Test;
public class RecordPatternAssertionExample {
record Point(int x, int y) {}
record Rectangle(Point topLeft, Point bottomRight) {}
@Test
public void testRectangleProperties() {
Rectangle rectangle = new Rectangle(new Point(1, 2), new Point(5, 6));
// Using record pattern for destructuring in assertions
if (rectangle instanceof Rectangle(Point(int x1, int y1), Point(int x2, int y2))) {
Assert.assertEquals(x1, 1, "Top-left x coordinate should be 1");
Assert.assertEquals(y1, 2, "Top-left y coordinate should be 2");
Assert.assertEquals(x2, 5, "Bottom-right x coordinate should be 5");
Assert.assertEquals(y2, 6, "Bottom-right y coordinate should be 6");
// Calculate and assert width and height
int width = x2 - x1;
int height = y2 - y1;
Assert.assertEquals(width, 4, "Rectangle width should be 4");
Assert.assertEquals(height, 4, "Rectangle height should be 4");
} else {
Assert.fail("Record pattern matching failed");
}
}
}
Pattern Matching for Switch in Assertions
Using Java 21's pattern matching for switch to create more flexible assertions:
import org.testng.Assert;
import org.testng.annotations.Test;
public class PatternMatchingSwitchAssertionExample {
sealed interface Shape permits Circle, Rectangle, Triangle {}
record Circle(double radius) implements Shape {}
record Rectangle(double width, double height) implements Shape {}
record Triangle(double base, double height) implements Shape {}
@Test
public void testShapeArea() {
Shape[] shapes = {
new Circle(5.0),
new Rectangle(4.0, 5.0),
new Triangle(3.0, 4.0)
};
for (Shape shape : shapes) {
double expectedArea = switch (shape) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Rectangle r -> r.width() * r.height();
case Triangle t -> 0.5 * t.base() * t.height();
};
double actualArea = calculateArea(shape);
Assert.assertEquals(actualArea, expectedArea, 0.001,
"Area calculation for " + shape.getClass().getSimpleName() + " is incorrect");
}
}
private double calculateArea(Shape shape) {
return switch (shape) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Rectangle r -> r.width() * r.height();
case Triangle t -> 0.5 * t.base() * t.height();
};
}
}
Virtual Thread-Based Parallel Assertions
Using Java 21's virtual threads to perform assertions in parallel:
import org.testng.Assert;
import org.testng.annotations.Test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.ArrayList;
import java.util.List;
public class ParallelAssertionExample {
@Test
public void testParallelAssertions() throws Exception {
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
List<Future<Boolean>> futures = new ArrayList<>();
// Submit assertion tasks to run in parallel
for (Integer number : numbers) {
futures.add(executor.submit(() -> {
// Perform some time-consuming validation
Thread.sleep(100);
boolean isPrime = isPrime(number);
boolean isEven = number % 2 == 0;
// Assertions for this number
if (number == 2) {
Assert.assertTrue(isPrime, number + " should be prime");
Assert.assertTrue(isEven, number + " should be even");
} else if (isEven) {
Assert.assertFalse(isPrime, number + " should not be prime");
} else if (number > 2) {
// For odd numbers > 2, check primality
if (number == 3 || number == 5 || number == 7) {
Assert.assertTrue(isPrime, number + " should be prime");
} else {
Assert.assertFalse(isPrime, number + " should not be prime");
}
}
return true; // Task completed successfully
}));
}
// Wait for all assertion tasks to complete
for (Future<Boolean> future : futures) {
future.get(); // This will throw an exception if any assertion failed
}
}
}
private boolean isPrime(int number) {
if (number <= 1) return false;
if (number <= 3) return true;
if (number % 2 == 0 || number % 3 == 0) return false;
for (int i = 5; i * i <= number; i += 6) {
if (number % i == 0 || number % (i + 2) == 0) return false;
}
return true;
}
}