← Back to Blog

April 02, 2026 · 20 views

Making Your Java Test Assertions Self-Documenting

Java testing JUnit 5 Hamcrest SLF4J QA automation test logging CI/CD API testing SWQA InformativeAssertionLog

Table of contents

  1. What is InformativeAssertionLog?
  2. The problem it solves
  3. Code walkthrough
  4. When to use it — and when not to
  5. Real-world usage examples
  6. Setup and dependencies


1. What is InformativeAssertionLog?

InformativeAssertionLog is a thin utility class that wraps JUnit 5's Assertions and Hamcrest's MatcherAssert with structured SLF4J logging. Every assertion it makes is automatically logged — including the human-readable message, the expected value, and the actual value — before the underlying assertion is evaluated.

The result: test logs that read like a specification, not a wall of cryptic failure messages.

Core idea: Instead of reading "AssertionError: expected true but was false", your CI logs now say "Assert that HTTP response status is 200 — expected: 200 — actual: 404". No more guessing what went wrong.

2. The problem it solves

Standard JUnit 5 and Hamcrest assertions are excellent at catching failures, but their log output at runtime is minimal. When a test suite with hundreds of assertions fails in CI, you're often left with a bare stack trace pointing to a line number. You must open the source code, find the assertion, and mentally reconstruct what was being checked.

This becomes especially painful in three scenarios:


3. Code walkthrough

Here is the full class, with annotations on each method:


import org.apache.commons.lang3.StringUtils;
import org.hamcrest.Matcher;
import org.hamcrest.MatcherAssert;
import org.junit.jupiter.api.Assertions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;


public class InformativeAssertionLog {
    private static final String MESSAGE_EXPECTED_ACTUAL = " {}{} - expected: {}{} - actual: {}";
    private static Logger logger = LoggerFactory.getLogger(InformativeAssertionLog.class);


    public static void assertTrue(String message, boolean condition) {
        String fullMessage = "Assert that " + message;
        logger.info(MESSAGE_EXPECTED_ACTUAL, fullMessage, System.lineSeparator(), Boolean.TRUE, System.lineSeparator(), condition);
        Assertions.assertTrue(condition, fullMessage);
    }

    public static void assertFalse(String message, boolean condition) {
        String fullMessage = "Assert that " + message;
        logger.info(MESSAGE_EXPECTED_ACTUAL, fullMessage, System.lineSeparator(), Boolean.FALSE, System.lineSeparator(), condition);
        Assertions.assertFalse(condition,fullMessage);
    }

    public static <T> void assertThat(String message, T actual, Matcher<? super T> matcher) {
        assertThat(message, "", actual, matcher);
    }

    public static <T> void assertThat(String logMessage, String failureMessage, T actual, Matcher<? super T> matcher) {
        String fullMessage = "Assert that " + logMessage;
        logger.info(MESSAGE_EXPECTED_ACTUAL, fullMessage, System.lineSeparator(), matcher.toString(), System.lineSeparator(), actual);
        if (StringUtils.isEmpty(failureMessage)) {
            MatcherAssert.assertThat(actual, matcher);
        } else {
            MatcherAssert.assertThat(failureMessage, actual, matcher);
        }
    }

    public static <T> void assertThat(String message, List<T> param, String failureMessage, T actual, Matcher<? super T> matcher) {
        logger.info(message, param);
        assertThat(message, failureMessage, actual, matcher);
    }
}


4. When to use it — and when not to

Use InformativeAssertionLog when:

Consider alternatives when:


5. Real-world usage examples

API response validation

@Test
void userProfileReturnsExpectedFields() {
    Response response = userApi.getProfile("user-42");

    // Logs: "Assert that response status is 200 - expected: <200> - actual: 200"
    InformativeAssertionLog.assertThat(
        "response status is 200",
        response.getStatusCode(),
        equalTo(200)
    );

    // Logs: "Assert that username field is not null or empty - expected: not null ..."
    InformativeAssertionLog.assertThat(
        "username field is not null or empty",
        response.jsonPath().getString("username"),
        notNullValue()
    );
}


Parameterised test data logging


@ParameterizedTest
@MethodSource("provideUserRoles")
void eachRoleHasCorrectPermissions(String role, List<String> expectedPerms) {

    // Lists the expected perms in the log line for this iteration
    InformativeAssertionLog.assertThat(
        "role {} should have permissions: {}",
        List.of(role, expectedPerms),
        "permission list mismatch for role: " + role,
        permissionService.getPermissions(role),
        containsInAnyOrder(expectedPerms.toArray())
    );
}


6. Setup and dependencies

Add the following to your pom.xml. All of these are likely already present in a typical Spring Boot or REST Assured project:


<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.10.2</version> <!-- Using a recent stable version -->
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>2.0.17</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j2-impl</artifactId>
    <version>2.25.4</version>
</dependency>
<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest</artifactId>
    <version>3.0</version>
</dependency>
<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest</artifactId>
    <version>3.0</version>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.20.0</version>
</dependency>


📚 How to Cite This Article

APA Format:

I enjoy building things that live on the internet. (2026). Making Your Java Test Assertions Self-Documenting. Steti.info. https://steti.info/blog/making-your-lava-test-Log-junit-5-log-expected-and-actual-results

MLA Format:

I enjoy building things that live on the internet. "Making Your Java Test Assertions Self-Documenting." Steti.info, 02 Apr. 2026. https://steti.info/blog/making-your-lava-test-Log-junit-5-log-expected-and-actual-results.

Chicago Style:

I enjoy building things that live on the internet. "Making Your Java Test Assertions Self-Documenting." Steti.info. April 02, 2026. https://steti.info/blog/making-your-lava-test-Log-junit-5-log-expected-and-actual-results.

Published: April 02, 2026
Last Updated: April 03, 2026

About the Author

Author
I like to build from websites to web apps, I create digital experiences that solve real problems and delight users and the most important is that all that I build, I build with PEOPLE!
Learn more about the author →

Related Posts