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(…).