JUnit 5 Assertions — Complete Guide
Assertions are the verdict of your test — they determine pass or fail. JUnit 5 provides rich assertions, and AssertJ adds fluent readability.
Basic Assertions
import static org.junit.jupiter.api.Assertions.*;
@Test
void basicAssertions() {
// Equality
assertEquals(4, 2 + 2);
assertEquals("hello", "HELLO".toLowerCase());
assertNotEquals("foo", "bar");
// Boolean
assertTrue(10 > 5);
assertFalse("".length() > 0);
// Null checks
assertNull(null);
assertNotNull("value");
assertNotNull(new ArrayList<>());
}
Custom Failure Messages
@Test
void withMessages() {
User user = userService.findById(1L);
assertNotNull(user, "User with ID 1 should exist in the database");
assertEquals("Alice", user.getName(),
() -> "Expected user name to be Alice but got " + user.getName());
}
Tip: Use lambda messages (
() -> "...") for expensive string construction — only evaluated on failure.
assertThrows — Testing Exceptions
@Test
void shouldThrowOnNullInput() {
IllegalArgumentException ex = assertThrows(
IllegalArgumentException.class,
() -> StringUtils.reverse(null)
);
assertEquals("Input cannot be null", ex.getMessage());
}
@Test
void shouldNotThrow() {
assertDoesNotThrow(() -> StringUtils.reverse("hello"));
}
assertAll — Grouped Assertions
Without assertAll, the test stops at the first failure. With it, all assertions run:
@Test
void shouldCreateUserWithAllFields() {
User user = userService.createUser("Alice", "alice@example.com");
assertAll("user",
() -> assertNotNull(user.getId()),
() -> assertEquals("Alice", user.getName()),
() -> assertEquals("alice@example.com", user.getEmail()),
() -> assertNotNull(user.getCreatedAt()),
() -> assertTrue(user.isActive())
);
}
If multiple assertions fail, you see all failures — not just the first one.
assertTimeout — Performance Assertions
@Test
void shouldCompleteQuickly() {
assertTimeout(Duration.ofSeconds(2), () -> {
// This must complete within 2 seconds
service.processOrder(orderId);
});
}
// With return value
@Test
void shouldReturnResultQuickly() {
String result = assertTimeout(Duration.ofMillis(500), () -> {
return service.fetchData();
});
assertNotNull(result);
}
assertTimeoutPreemptively()aborts after the timeout (runs in a separate thread). Use with caution — it can leave resources in an inconsistent state.
Collection Assertions
@Test
void collectionAssertions() {
List<String> expected = List.of("Alice", "Bob", "Charlie");
List<String> actual = userService.getAllNames();
// Exact match (order matters)
assertIterableEquals(expected, actual);
// Array equality
assertArrayEquals(
new int[]{1, 2, 3},
new int[]{1, 2, 3}
);
}
Floating-Point Assertions
@Test
void floatingPointEquality() {
// ❌ Fragile — floating-point precision issues
// assertEquals(0.3, 0.1 + 0.2);
// ✅ Use delta
assertEquals(0.3, 0.1 + 0.2, 0.0001);
}
assertSame / assertNotSame — Reference Equality
@Test
void referenceEquality() {
String a = new String("hello");
String b = new String("hello");
assertEquals(a, b); // ✅ passes — same value
assertNotSame(a, b); // ✅ passes — different objects
String c = a;
assertSame(a, c); // ✅ passes — same reference
}
AssertJ — Fluent Assertions (Alternative)
AssertJ provides a more readable, discoverable API:
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.26.0</version>
<scope>test</scope>
</dependency>
import static org.assertj.core.api.Assertions.*;
@Test
void assertJExample() {
String name = "Alice";
assertThat(name)
.isNotNull()
.isNotEmpty()
.startsWith("Ali")
.hasSize(5);
}
@Test
void assertJCollections() {
List<User> users = userService.findAll();
assertThat(users)
.hasSize(3)
.extracting(User::getName)
.containsExactly("Alice", "Bob", "Charlie");
}
@Test
void assertJExceptions() {
assertThatThrownBy(() -> userService.findById(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("cannot be null");
}
Why AssertJ?
| Feature | JUnit 5 | AssertJ |
|---|---|---|
| Readability | OK | ✅ Fluent chain |
| IDE autocomplete | Limited | ✅ Start typing assertThat(x). |
| Collection assertions | Basic | ✅ extracting, filteredOn, containsOnly |
| Exception assertions | assertThrows |
✅ assertThatThrownBy with chaining |
| Soft assertions | assertAll |
✅ SoftAssertions |
Assertion Cheat Sheet
| Assertion | Use When |
|---|---|
assertEquals(expected, actual) |
Comparing values |
assertTrue(condition) |
Boolean check |
assertNull(value) |
Null check |
assertThrows(Exception.class, ...) |
Expected exception |
assertAll(...) |
Multiple assertions, see all failures |
assertTimeout(duration, ...) |
Performance check |
assertIterableEquals(...) |
List/collection equality |
assertThat(x).isEqualTo(y) |
AssertJ fluent style |
Common Mistakes
| Mistake | Fix |
|---|---|
assertEquals(actual, expected) — wrong order |
Expected first, actual second |
| Missing delta for doubles | Use assertEquals(0.3, val, 0.001) |
Single assertion per assertAll |
Group related assertions together |
| Not checking exception message | Use assertThrows + getMessage() |
Key Takeaways
assertEquals— expected first, actual second.assertThrows— test exceptions and verify messages.assertAll— run all assertions, see all failures at once.- Use delta for floating-point comparisons.
- Consider AssertJ for fluent, readable assertions.
What’s Next?
Next: Parameterized Tests — run the same test with different inputs automatically.