Incomplete Assertion Builder

ID

java.assertions_complete

Severity

critical

Remediation Complexity

medium

Remediation Risk

low

Remediation Effort

medium

Resource

Code Smell

Language

Java

Tags

assertion, reliability, testing

Description

Reports a Fest, AssertJ, Google Truth or Mockito assertion entry point — assertThat(…​), verify(…​) — called with no verification method chained onto it.

Rationale

assertThat(…​) and verify(…​) return a builder, not a finished check. The builder only becomes an assertion once a verification method is chained onto it; left bare, the statement constructs the builder and throws it away, so the test passes whether or not the code under test behaves as expected.

boolean approved = reviewer.approve(request);
assertThat(approved); // nothing is actually checked

List<String> log = Mockito.mock(List.class);
log.add("submitted");
Mockito.verify(log); // no method is chained onto verify(), so nothing is verified

Remediation

Chain the verification the test meant to make.

boolean approved = reviewer.approve(request);
assertThat(approved).isTrue();

List<String> log = Mockito.mock(List.class);
log.add("submitted");
Mockito.verify(log).add("submitted");

What is not reported

JUnit and Hamcrest’s two- and three-argument assertThat(actual, matcher) is a complete assertion on its own — a different API entirely from the single-argument builder forms this rule targets, and told apart from them by its argument count when both are statically imported side by side.

assertThatThrownBy(…​) and BDD’s thenThrownBy(…​) are complete assertions too: they raise the failure themselves when the code under test throws nothing, so a bare call checks something.

A bare call whose result is handed on rather than discarded — assigned to a variable, returned, passed as an argument to another call, or produced as an expression lambda’s result — is left alone: that is the shape of a helper that hands the incomplete builder onward for someone else to finish the chain.

Any further chaining at all is accepted as complete — a chain that continues onto an AssertJ description or configuration method (.as(…​), .describedAs(…​), .overridingErrorMessage(…​), .usingComparator(…​)) without ever reaching a real verification method is not detected, nor is SoftAssertions’ separate, method-spanning requirement to call `assertAll() after every assertThat(…​).

© 2026 Xygeni. All rights reserved