AssertJ is a fluent assertion library that works with JUnit and TestNG. Instead of assertEquals(expected, actual), you chain readable checks from the actual value, assertThat(names).hasSize(3).contains("Alice"), and get far clearer failure messages, especially for collections and objects.

// AssertJ: more readable assertions than JUnit's assertEquals
import static org.assertj.core.api.Assertions.*;

// Basic assertions
assertThat("Hello World")
    .isNotNull()
    .isNotEmpty()
    .startsWith("Hello")
    .endsWith("World")
    .contains("lo W")
    .hasSize(11)
    .isEqualToIgnoringCase("hello world");

// Number assertions
assertThat(42)
    .isPositive()
    .isGreaterThan(10)
    .isLessThanOrEqualTo(100)
    .isBetween(0, 100)
    .isEven();

// Collection assertions
List<String> names = List.of("Alice", "Bob", "Charlie");
assertThat(names)
    .hasSize(3)
    .contains("Alice", "Bob")
    .containsExactly("Alice", "Bob", "Charlie")
    .doesNotContain("Dave")
    .allMatch(s -> s.length() > 2)
    .anyMatch(s -> s.startsWith("A"))
    .noneMatch(String::isEmpty);

// Object assertions
User user = new User("Alice", 30, "alice@test.com");
assertThat(user)
    .isNotNull()
    .hasFieldOrPropertyWithValue("name", "Alice")
    .hasFieldOrPropertyWithValue("age", 30);

// Exception assertions
assertThatThrownBy(() -> Integer.parseInt("abc"))
    .isInstanceOf(NumberFormatException.class)
    .hasMessageContaining("abc");

assertThatCode(() -> safeMethod()).doesNotThrowAnyException();

// Custom error message
assertThat(user.getAge())
    .as("User age should be adult")
    .isGreaterThanOrEqualTo(18);

Setup

<dependency>
  <groupId>org.assertj</groupId>
  <artifactId>assertj-core</artifactId>
  <version>3.26.0</version>   <!-- check Maven Central for the latest -->
  <scope>test</scope>
</dependency>
Advertisement

Extracting Values from Lists of Objects

List<Product> products = api.getProducts();

assertThat(products)
    .extracting(Product::name)
    .containsExactly("Backpack", "Bike Light", "Bolt T-Shirt");

assertThat(products)
    .extracting(Product::name, Product::price)
    .contains(tuple("Backpack", 29.99));

assertThat(products).filteredOn(p -> p.price() > 20).hasSize(2);

Comparing Whole Objects

// Field-by-field comparison without needing equals(), ignoring generated fields
assertThat(actualUser)
    .usingRecursiveComparison()
    .ignoringFields("id", "createdAt")
    .isEqualTo(expectedUser);

Soft Assertions

SoftAssertions.assertSoftly(softly -> {
    softly.assertThat(page.getTitle()).isEqualTo("Checkout");
    softly.assertThat(page.getTotal()).isEqualTo("₹1,299");
    softly.assertThat(page.isPayButtonEnabled()).isTrue();
});   // reports all failures together

assertSoftly calls assertAll() for you, which avoids the classic TestNG SoftAssert bug of forgetting it.

Most-Used AssertJ Assertions

TypeAssertions
Any objectisEqualTo, isNotNull, isInstanceOf, isIn, usingRecursiveComparison()
Stringcontains, startsWith, matches(regex), isEqualToIgnoringCase, isBlank
NumberisPositive, isBetween, isCloseTo(x, within(0.01))
CollectionhasSize, contains, containsExactly, containsExactlyInAnyOrder, isSorted, allMatch, extracting
MapcontainsKey, containsEntry, doesNotContainKey
ExceptionassertThatThrownBy(...), isInstanceOf, hasMessageContaining, assertThatCode(...).doesNotThrowAnyException()
OptionalisPresent, isEmpty, hasValue

AssertJ in UI and API Tests

// Selenium: verify sorted prices on a listing page
List<Double> prices = driver.findElements(By.cssSelector(".price")).stream()
        .map(e -> Double.parseDouble(e.getText().replaceAll("[^0-9.]", "")))
        .toList();
assertThat(prices).as("prices sorted low to high").isSorted();

// REST Assured: deserialize, then assert with AssertJ
List<String> emails = given().get("/users").jsonPath().getList("data.email");
assertThat(emails).isNotEmpty().allMatch(e -> e.endsWith("@example.com"));

The as(...) description appears in the failure message, so a failing CI run tells you what was being checked without opening the code.

FAQs

Is AssertJ better than JUnit or TestNG assertions?

It is more readable and gives clearer failure messages, especially for collections and objects, and works with both frameworks. Many teams use AssertJ for assertions while keeping JUnit or TestNG as the runner.

Does AssertJ work with TestNG?

Yes. AssertJ only provides assertions, so it works with any runner; import org.assertj.core.api.Assertions.assertThat in your TestNG tests.

How do I add a custom message to an AssertJ assertion?

Call .as("description") (or .describedAs) before the assertion method; the text appears in the failure message.