JUnit5 Assertions
Basic Assertions
import static org.junit.jupiter.api.Assertions.*;
@Test
void basicAssertions() {
// Equality
assertEquals(4, 2 + 2);
assertEquals("hello", result.toLowerCase());
assertEquals(3.14, Math.PI, 0.01); // delta for doubles
// Null checks
assertNull(user.getMiddleName());
assertNotNull(response.getBody());
// Boolean
assertTrue(list.isEmpty());
assertFalse(user.isBanned());
// Reference equality
assertSame(singleton, Singleton.getInstance());
assertNotSame(obj1, obj2);
// Array equality (deep)
assertArrayEquals(new int[]{1, 2, 3}, actual);
// Iterable equality
assertIterableEquals(List.of("a", "b"), result);
// With failure message (last param or supplier)
assertEquals(200, response.getStatus(), "Expected OK status");
assertTrue(predicate, () -> "Computed message: " + computeExpected());
}
assertThrows & assertDoesNotThrow
@Test
void exceptionAssertions() {
// Assert specific exception is thrown
IllegalArgumentException ex = assertThrows(
IllegalArgumentException.class,
() -> service.create(null)
);
assertEquals("Name cannot be null", ex.getMessage());
// Assert exception type and cause
RuntimeException wrapped = assertThrows(RuntimeException.class,
() -> service.callExternal());
assertInstanceOf(IOException.class, wrapped.getCause());
// Assert NO exception is thrown
assertDoesNotThrow(() -> service.healthCheck());
// assertThrowsExactly โ no subclasses
assertThrowsExactly(
NullPointerException.class,
() -> parseNull()
);
}
assertAll โ Grouped Assertions
@Test
void userFieldsAreCorrect() {
User user = service.findById(1L);
// All assertions execute even if one fails
assertAll("user properties",
() -> assertEquals("Alice", user.getName()),
() -> assertEquals("alice@example.com", user.getEmail()),
() -> assertTrue(user.isActive()),
() -> assertNotNull(user.getCreatedAt())
);
}
// Nested assertAll
@Test
void addressIsValid() {
Address address = user.getAddress();
assertAll("full address check",
() -> assertAll("street",
() -> assertNotNull(address.getStreet()),
() -> assertFalse(address.getStreet().isBlank())
),
() -> assertNotNull(address.getCity()),
() -> assertEquals(5, address.getZipCode().length())
);
}
assertTimeout & assertTimeoutPreemptively
import java.time.Duration;
@Test
void operationCompletesInTime() {
// Fails if execution exceeds duration (waits for completion)
String result = assertTimeout(Duration.ofSeconds(2), () -> {
return processBigFile();
});
assertNotNull(result);
}
@Test
void operationAbortedIfTooSlow() {
// Interrupts execution if duration exceeded (different thread)
assertTimeoutPreemptively(Duration.ofMillis(500), () -> {
Thread.sleep(200); // This would fail if changed to 600
return fetchData();
});
}
// Note: assertTimeout uses same thread (ThreadLocal state works)
// assertTimeoutPreemptively uses new thread (ThreadLocal state lost)
Assumptions โ assumeTrue / assumingThat
import static org.junit.jupiter.api.Assumptions.*;
@Test
void onlyRunOnLinux() {
assumeTrue("Linux".equals(System.getProperty("os.name")));
// Test only runs on Linux, skipped otherwise (not failed)
}
@Test
void onlyRunWithRealDatabase() {
assumeTrue(System.getenv("USE_REAL_DB") != null,
"Skipping: USE_REAL_DB env var not set");
// ...
}
@Test
void conditionalBehavior() {
assumingThat(
Boolean.getBoolean("ci.build"),
() -> {
// Only runs in CI
assertEquals(0, getWarnings().size());
}
);
// This always runs:
assertNotNull(mainResult);
}
Custom Assertions with AssertJ
// Add AssertJ for fluent, readable assertions
// Maven: org.assertj:assertj-core:3.x
import static org.assertj.core.api.Assertions.*;
@Test
void assertJExamples() {
// Strings
assertThat("Hello World")
.startsWith("Hello")
.containsIgnoringCase("world")
.hasSize(11);
// Collections
assertThat(list)
.hasSize(3)
.contains("apple", "banana")
.doesNotContain("cherry");
// Objects
assertThat(user)
.extracting("name", "email")
.containsExactly("Alice", "alice@example.com");
// Exceptions
assertThatThrownBy(() -> service.divide(1, 0))
.isInstanceOf(ArithmeticException.class)
.hasMessage("/ by zero");
// Numbers
assertThat(price).isBetween(9.99, 29.99);
}