AssertJ: readable assertions and soft assertions
AssertJ is a library of fluent assertions. Everything starts with assertThat(actual), followed by a chain of methods that the IDE suggests:
import static org.assertj.core.api.Assertions.assertThat;
assertThat(user.name()).isEqualTo("Anna");
assertThat(names).hasSize(3).contains("Anna").doesNotHaveDuplicates();
assertThat(price).isBetween(10, 100);
assertThat(order).usingRecursiveComparison().isEqualTo(expectedOrder);
Its advantage over a plain assertEquals is a clear failure message ("Expecting … to contain …") and the "actual first, then expected" order without mixing up arguments. usingRecursiveComparison() compares objects field by field without an overridden equals, and extracting pulls fields out of a list of objects. For exceptions: assertThatThrownBy(() -> ...).isInstanceOf(X.class).hasMessageContaining("...").
Soft assertions do not stop at the first failure; they collect all of them and report together. Useful when several independent fields are checked and you want the whole picture in one run:
SoftAssertions.assertSoftly(softly -> {
softly.assertThat(user.name()).isEqualTo("Anna");
softly.assertThat(user.role()).isEqualTo("admin");
softly.assertThat(user.active()).isTrue();
});
In assertSoftly the verification runs automatically at the end of the block. If you create new SoftAssertions() by hand you must call softly.assertAll(): without it failures are ignored and the test turns green. In JUnit 5 you can attach SoftAssertionsExtension with an @InjectSoftAssertions field.
When not to use them: when the next check depends on the previous one (there is no point checking a field if the object is null): there you need a regular, hard assertion.
JUnit 5 and TestNG have their own Assertions, and Hamcrest has assertThat(actual, is(expected)) (REST Assured uses its matchers). For new code AssertJ is more convenient.