skip to content

Assumptions

Assumptions abort a test as skipped rather than failing it when a precondition does not hold, such as an environment-specific dependency. The assumption-versus-assertion distinction is the point interviewers check.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

4

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

open as a page

Walk through the assumeTrue and assumeFalse APIs in JUnit 5. What overloads exist (boolean vs BooleanSupplier, custom message), and what is a common use case?

level: middleimportance: should knowfreq 40%

basics

~20 s

assumeTrue(condition) keeps running the test only if the condition is true; assumeFalse(condition) keeps running only if it is false. Otherwise the test is skipped. Both can take a message, and both have a version that takes a BooleanSupplier so the condition is only evaluated lazily.

open as a page

How does assumingThat differ from assumeTrue in JUnit 5? Explain its two-argument form and when you would reach for it.

level: seniorimportance: should knowfreq 30%

basics

~20 s

assumeTrue aborts the whole test when its condition is false. assumingThat takes a condition AND a block of code (an Executable): it runs that block only if the condition is true, and otherwise just skips the block and lets the rest of the test continue normally. It does not abort the test.

open as a page

What are the consequences for test reporting, lifecycle callbacks, and coverage metrics when tests are aborted by assumptions? Why can heavy use of assumptions be risky at scale?

level: principalimportance: nice to knowfreq 18%

basics

~20 s

An aborted test counts as 'skipped', not 'passed' and not 'failed'. Lifecycle teardown still runs, but the test's body did not. Skipped tests do not exercise your code, so they contribute nothing to coverage. If many tests silently skip in CI, you can have a green build that actually tested very little.

open as a page