skip to content

In JUnit 5, what is the difference between an assumption (assumeTrue) and an assertion (assertTrue)? What happens to a test when each one fails?

level: juniorimportance: must knowfreq 55%

answer

  1. Assertion fails = RED; assumption fails = SKIPPED/green
  2. Assertions package vs Assumptions package
  3. Assumption throws TestAbortedException
  4. Assertion = code under test; assumption = precondition/environment
  5. Code after a failed assumption does not run

basics

~20 s

An assertion checks the result you are testing: if it is false, the test FAILS. An assumption checks a precondition: if it is false, the test is SKIPPED (aborted), not failed. So a failed assumption is treated like a test that did not run.

solid answer

~40 s

Assertions and assumptions both take a boolean, but they answer different questions. An assertion (assertTrue/assertEquals) verifies the behavior under test; if it is false, JUnit marks the test as FAILED and the build goes red. An assumption (assumeTrue/assumeFalse) verifies a precondition the test needs to be meaningful; if it is false, JUnit throws a TestAbortedException and the test is reported as SKIPPED/ABORTED, not failed. The build stays green. The intent matters: use assumptions for environmental gates ('only run this if we are on Linux' or 'only if a DB env var is set'), and assertions for the thing you actually want to prove. Code that appears AFTER a failed assumption does not execute, because the abort exception unwinds the test method immediately.

code

java · 12 lines
java
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import org.junit.jupiter.api.Test;

class PaymentTest {
    @Test
    void chargesInProductionOnly() {
        assumeTrue("prod".equals(System.getenv("STAGE")));
        // SKIPPED (not failed) when STAGE != prod
        assertEquals(100, charge(100)); // the actual claim about behavior
    }
}

go deeper

for a junior

Knows assertion failure = test fails (red), assumption failure = test skipped (green), and that they come from different classes.

for a middle

Can articulate the intent split (precondition vs behavior), names TestAbortedException vs AssertionFailedError, and knows the rest of the method is skipped after a failed assumption.

for a senior

Explains when to prefer an assumption over an annotation-based condition, knows teardown still runs on abort, and avoids overusing assumptions to mask real failures.

for a principal

Frames assumptions as part of keeping the test-suite signal honest (skip ≠ pass ≠ fail), and can advise team conventions on when skipping is acceptable vs when a test should be excluded or fixed.

## What this is about A **unit test** is a small method that runs a piece of your code and checks the result. **JUnit 5** (also called JUnit Jupiter) is the standard library for writing such tests in Java. Inside a test you use two families of checks that look similar but mean opposite things: **assertions** and **assumptions**. ## Assertions — verify the thing under test An **assertion** is a statement you claim must be true about your code's behavior. Methods live in `org.junit.jupiter.api.Assertions`: `assertTrue`, `assertEquals`, `assertThrows`, etc. If the claim is false, the assertion throws an `AssertionError` (specifically an `AssertionFailedError`), JUnit catches it, and the test is reported as **FAILED**. A failed test turns the build red — it signals a real defect. ```java assertEquals(4, calculator.add(2, 2)); // if not 4 → test FAILS ``` ## Assumptions — verify a precondition An **assumption** is a statement about the *environment or context* the test needs in order to be meaningful — not about the code's correctness. Methods live in `org.junit.jupiter.api.Assumptions`: `assumeTrue`, `assumeFalse`, `assumingThat`. If the assumption is **false**, JUnit throws a `TestAbortedException`, and the test is reported as **SKIPPED / ABORTED** — *not* failed. The build stays green. ```java assumeTrue("CI".equals(System.getenv("ENV"))); // false → test is SKIPPED // everything below here is skipped too ``` ## The key contrast | | Assertion | Assumption | |---|---|---| | Package | `Assertions` | `Assumptions` | | Checks | the behavior under test | a precondition / environment | | On false | **FAIL** (red build) | **SKIP/ABORT** (green build) | | Exception thrown | `AssertionFailedError` (an `AssertionError`) | `TestAbortedException` | | Meaning | 'the code is wrong' | 'this test does not apply here' | ## Why it matters Failing a test that simply can't run in the current environment (no database, wrong OS) is misleading — it hides real failures in noise. An assumption lets you say 'if the precondition is not met, just don't run me, and don't complain.' That keeps the failure signal honest: red means a genuine bug. ## Control flow note Both assertions and assumptions work by **throwing an exception** when they fail. That exception immediately unwinds the test method, so any code written after a failed assumption (or assertion) does **not** execute. The one exception is `assumingThat`, covered separately, which only gates a lambda rather than aborting the whole method.

  • If an assumption fails, does the @AfterEach teardown still run?
    Yes. An aborted test still went through the lifecycle, so @AfterEach (and @AfterAll) callbacks still execute. The test is reported as aborted/skipped, but teardown is not bypassed.
  • Which exception type does a failed assumeTrue throw, and which does a failed assertTrue throw?
    A failed assumeTrue throws org.opentest4j.TestAbortedException (caught as 'aborted'); a failed assertTrue throws org.opentest4j.AssertionFailedError, an AssertionError subclass (caught as 'failed').

An assertion is the exam itself — fail it and you flunk. An assumption is the eligibility check at the door: if you do not meet the prerequisite, you are simply turned away (not run), you do not get a failing grade.

saying these in an interview costs you the question

  • Saying a failed assumption makes the test FAIL — it makes it SKIP/abort.
  • Using an assumption to check the actual behavior under test (that should be an assertion).
  • Thinking assertions and assumptions come from the same class — they are Assertions vs Assumptions.
  • Claiming code after a failed assumption still runs — it does not (the method is aborted).

context