Assertion Swallowed By Its Own Catch
ID |
java.assertion_methods_try_block_try |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
Java |
Tags |
assertion, reliability, testing |
Description
Reports a JUnit or AssertJ assertion, or a fail(…) call, made directly in the try block of a try-catch whose matching catch clause targets AssertionError (or a broader type that also catches it, such as Error or Throwable) without ever referencing the caught exception.
Rationale
AssertionError is exactly what a failed assertion throws. Catching it right next to the assertion swallows the very failure the assertion exists to report, so the test passes whether or not the assertion actually held.
@Test
void rejectsInvalidInvoice() {
try {
validateInvoice(invoice);
fail("Expected an AssertionError"); // caught below and discarded
} catch (AssertionError e) {
}
}
Remediation
Prefer the dedicated exception-testing API, or, if the try-catch is kept, inspect the caught exception to confirm it is the one expected.
@Test
void rejectsInvalidInvoice() {
assertThrows(AssertionError.class, () -> validateInvoice(invoice));
}
@Test
void rejectsInvalidInvoiceWithMessage() {
try {
validateInvoice(invoice);
fail("Expected an AssertionError");
} catch (AssertionError e) {
assertThat(e.getMessage()).contains("invalid");
}
}
What is not reported
Only a call that runs as part of the try block’s own control flow counts: an assertion reached only through a nested method, lambda, or a local or anonymous class declared inside the try is not flagged, because that code executes later, if at all, not as part of the try. A catch clause targeting an unrelated exception type is out of scope; multiple catch clauses matching AssertionError or a supertype suppress the finding as soon as one of them references its exception, however lightly.