AssertJ generates informative error messages by default, but sometimes a domain-specific message is more useful to the person reading a CI failure log. The methods withFailMessage() and overridingErrorMessage() replace the default AssertJ message entirely with your own text.
withFailMessage vs overridingErrorMessage
Both methods are functionally identical — withFailMessage was added as a more readable alias. Use either to supply a static message string or, for expensive-to-build messages, a Supplier<String> so the message is only constructed on failure.
Important: Must Come Before the Assertion
Like as(), these methods must be called before the assertion itself. Placing them after the assertion has no effect because a failing assertion throws immediately.
// CORRECT
assertThat(value).withFailMessage("Expected active user").isTrue();
// WRONG - message ignored
assertThat(value).isTrue().withFailMessage("Expected active user");
Lazy Message (Supplier)
When the message construction is costly (e.g., involves I/O or reflection), use the Supplier<String> variant to defer evaluation:
assertThat(result).withFailMessage(() -> "Computed: " + buildReport()).isNotNull();
Example
package com.logicbig.example;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;
public class CustomErrorMessageExample {
@Test
void myTest() {
String status = "ACTIVE";
// withFailMessage before assertion
assertThat(status).withFailMessage("User status must be ACTIVE")
.isEqualTo("ACTIVE");
System.out.println("withFailMessage passed");
// overridingErrorMessage (alias)
assertThat(42).overridingErrorMessage("Score should be positive")
.isPositive();
System.out.println("overridingErrorMessage passed");
// lazy supplier - message built only on failure
String user = "bob";
assertThat(user).withFailMessage(() -> "User '" + user + "' is invalid")
.isNotBlank();
System.out.println("Lazy message passed");
}
}
Output$ mvn clean test -Dtest=* [INFO] Scanning for projects... [INFO] [INFO] ---------< com.logicbig.example:assertj-custom-error-message >---------- [INFO] Building assertj-custom-error-message 1.0-SNAPSHOT [INFO] from pom.xml [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- clean:3.2.0:clean (default-clean) @ assertj-custom-error-message --- [INFO] [INFO] --- resources:3.3.1:resources (default-resources) @ assertj-custom-error-message --- [INFO] skip non existing resourceDirectory D:\example-projects\assertj\assertj-custom-error-message\src\main\resources [INFO] [INFO] --- compiler:3.11.0:compile (default-compile) @ assertj-custom-error-message --- [INFO] No sources to compile [INFO] [INFO] --- resources:3.3.1:testResources (default-testResources) @ assertj-custom-error-message --- [INFO] skip non existing resourceDirectory D:\example-projects\assertj\assertj-custom-error-message\src\test\resources [INFO] [INFO] --- compiler:3.11.0:testCompile (default-testCompile) @ assertj-custom-error-message --- [INFO] Changes detected - recompiling the module! :source [INFO] Compiling 1 source file with javac [debug target 17] to target\test-classes [INFO] [INFO] --- surefire:3.2.5:test (default-test) @ assertj-custom-error-message --- [INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider [WARNING] file.encoding cannot be set as system property, use <argLine>-Dfile.encoding=...</argLine> instead [INFO] [INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- [INFO] Running com.logicbig.example.CustomErrorMessageExample withFailMessage passed overridingErrorMessage passed Lazy message passed [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.088 s -- in com.logicbig.example.CustomErrorMessageExample [INFO] [INFO] Results: [INFO] [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 2.255 s [INFO] Finished at: 2026-03-03T13:43:11+08:00 [INFO] ------------------------------------------------------------------------
Conclusion
The example passes all assertions with custom messages configured. The value of withFailMessage is visible in test failure scenarios — the domain-specific text replaces AssertJ's generic comparison output, making it immediately clear what the test was checking without reading the assertion code.
Example ProjectDependencies and Technologies Used: - assertj-core 3.27.7 (Rich and fluent assertions for testing in Java)
- junit-jupiter-engine 6.0.2 (Module "junit-jupiter-engine" of JUnit)
- JDK 17
- Maven 3.9.11
|