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?
answer
- assumeTrue continues if true; assumeFalse continues if false
- Overloads: boolean, BooleanSupplier (lazy), + message / Supplier<String>
- assumeFalse(x) == assumeTrue(!x)
- Typical use: OS/env/resource gating
- Annotations for static gates; assume* for dynamic ones
basics
~20 sassumeTrue(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.
solid answer
~40 sBoth methods live in org.junit.jupiter.api.Assumptions and are usually statically imported. assumeTrue aborts the test unless its condition is true; assumeFalse aborts unless its condition is false — they are mirror images, so you pick whichever reads more naturally. Each comes in overloads: a plain boolean, a BooleanSupplier (deferred evaluation, useful if computing the condition is expensive or might throw), and variants taking a String message or a Supplier<String> message that is shown when the test is aborted. A typical use is gating environment-specific tests: assumeTrue(System.getProperty('os.name').startsWith('Windows')) to skip a Windows-only test elsewhere, or assumeFalse(isRunningInCi()) to skip a flaky-on-CI test locally only. When the assumption holds, execution simply continues to the assertions; when it fails, JUnit throws TestAbortedException and marks the test skipped.
code
java · 13 linesimport static org.junit.jupiter.api.Assumptions.assumeTrue;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.jupiter.api.Test;
class IntegrationTest {
@Test
void hitsRealDatabase() {
// lazy BooleanSupplier + lazy message; both run only at the check
assumeTrue(() -> System.getenv("DB_URL") != null,
() -> "DB_URL not set — skipping integration test");
assertNotNull(connectToDb()); // only runs when DB_URL is present
}
}go deeper
Knows assumeTrue runs the test when the condition is true and assumeFalse when it is false, and that otherwise the test is skipped.
Names the boolean and BooleanSupplier overloads plus the message variants, and gives a concrete env/OS gating use case.
Distinguishes assume* (dynamic) from @Enabled*/@Disabled* annotations (static, declarative), and uses the lazy Supplier overloads to avoid eager/expensive evaluation.
Sets team guidance on environment-conditioned tests — preferring declarative annotations for static gates, reserving assume* for genuinely dynamic conditions, and watching that skips do not silently erode coverage.
## The two methods `org.junit.jupiter.api.Assumptions` provides two boolean gate methods that are mirror images of each other: - **`assumeTrue(condition)`** — continue the test only if `condition` is `true`; otherwise abort (skip). - **`assumeFalse(condition)`** — continue the test only if `condition` is `false`; otherwise abort (skip). They exist as a pair purely for readability: `assumeFalse(x)` is identical to `assumeTrue(!x)`, but one of the two usually reads more naturally for a given condition. ## Overloads Each method has several overloads. Conceptually: 1. **`assumeTrue(boolean)`** — the condition is already computed. 2. **`assumeTrue(BooleanSupplier)`** — the condition is a `() -> boolean` lambda, evaluated lazily *inside* the assumption call. This matters when computing the condition is expensive, or could throw, and you want that work to happen only at the point of the check. 3. **`assumeTrue(boolean, String message)`** and **`assumeTrue(boolean, Supplier<String> message)`** — attach a message shown when the test is aborted, explaining *why* it was skipped. The `Supplier<String>` form builds the message lazily (only when actually aborting). 4. Combinations: `assumeTrue(BooleanSupplier, String)` etc. `assumeFalse` mirrors all of these. ```java import static org.junit.jupiter.api.Assumptions.*; assumeTrue(dbReachable()); // boolean assumeTrue(() -> expensiveCheck()); // BooleanSupplier (lazy) assumeTrue(onLinux(), "only meaningful on Linux"); assumeFalse(isFridayDeploy(), () -> "skipping during " + window()); ``` ## What 'abort' means When the assumption is not satisfied, the method throws `org.opentest4j.TestAbortedException`. JUnit's engine treats that as **aborted** (skipped), so the build stays green. The message you supplied appears in the test report as the skip reason. Code after the failed assumption does not run. ## Common use cases - **OS / platform gating:** `assumeTrue(System.getProperty("os.name").startsWith("Windows"))`. - **Environment / config gating:** `assumeTrue(System.getenv("INTEGRATION") != null)`. - **Resource availability:** `assumeTrue(serviceIsUp())` — skip rather than fail when a dependency is down. - **Local-vs-CI differences:** `assumeFalse("true".equals(System.getenv("CI")))` to run a test only locally. ## A note on alternatives For *static, declarative* conditions, JUnit 5 also offers annotations like `@EnabledOnOs`, `@EnabledIfEnvironmentVariable`, and `@DisabledIfSystemProperty`. These decide *before* the test method starts and read more cleanly for simple gates. Reach for `assume*` when the decision is **dynamic** — computed inside the test body, possibly mid-way through setup — where an annotation can't express it.
- Why would you pass a BooleanSupplier instead of a plain boolean to assumeTrue?Lazy evaluation: with a plain boolean the condition is computed before the call regardless. A BooleanSupplier defers the computation to inside assumeTrue, so expensive or throwing logic runs only at the gate (and you can keep it tidy as a lambda).
- When would you prefer @EnabledIfEnvironmentVariable over assumeTrue?When the condition is static and known before the test runs. The annotation is declarative, shows up in the test's metadata, and disables the test up front (it never enters the method), which reads cleaner than an inline assume for simple environment gates.
assumeTrue and assumeFalse are two turnstiles facing opposite directions. One lets you through when the light is green; the other lets you through when the light is red. Either way, if the light is wrong for your turnstile, you simply do not enter — you are not penalized.
saying these in an interview costs you the question
- Claiming assumeFalse fails the test when its condition is true — it skips it.
- Thinking there is no message overload — there are String and Supplier<String> variants.
- Confusing assumeFalse(x) with asserting x is false; assumptions never fail the build.
- Believing the BooleanSupplier overload changes the skip/fail semantics — it only changes when the condition is evaluated.