Skip to content
Chapter 10 · JUnit 5 & Mockito

Assumptions ​

Chapter 5's assertions decide whether a test passes or fails. An assumption decides something else: whether a test should run at all, given the conditions it finds.

The need ​

Some tests should run only under a condition: a certain environment, a certain Java version. When the condition does not hold, the test should be skipped, not failed.

Why not a plain if?

java
@Test
void someTest() {
    if (a > b) {
        // test logic
    }
}

When the condition is false, the method simply returns, and the test is reported as passed, which is misleading: nothing was tested. We want it marked skipped (aborted): with ten tests and one condition false, nine run and one shows as skipped, none as failed.

Assumptions ​

The Assumptions class provides static methods (each with overloads, including one with a message):

java
assumeTrue(boolean condition)
assumeTrue(boolean condition, String message)

assumeFalse(boolean condition)
assumeFalse(boolean condition, String message)

assumingThat(boolean condition, Executable executable)

If the assumption does not hold, the test is aborted (skipped).

assumeTrue: skip if the condition is false ​

java
public class AssumptionTest {

    @BeforeEach
    void setup() {
        System.setProperty("env", "Prod");
    }

    @Test
    void testForDevelop() {
        Assumptions.assumeTrue("Dev".equals(System.getProperty("env")),
                "Test case is not eligible for this env");
        // test logic for Dev
    }

    @Test
    void testForProduction() {
        Assumptions.assumeTrue("Prod".equals(System.getProperty("env")));
        System.out.println("Test case can proceed");
    }
}
text
testForProduction()  ✔ passed     (prints "Test case can proceed")
testForDevelop()     ↷ aborted    Assumption failed: Test case is not eligible for this env

How it works. It is an if after all, with a twist: when the condition is false, it throws TestAbortedException (from org.opentest4j). The engine reports a test that ends with that exception as aborted, not failed. You could throw it yourself instead of using Assumptions:

java
throw new TestAbortedException("skipped by hand");   // reported as aborted

assumeFalse: run only if the condition is false ​

java
@Test
void testWithOldJavaVersion() {
    Assumptions.assumeFalse(Runtime.version().feature() == 21,
            "Test case is not eligible for this java version");
    // test logic
}

On Java 21 the condition is true, so the test is skipped with that message; on any other version it runs.

assumingThat: a conditional block ​

java
@Test
void testAssumingThat() {
    Assumptions.assumingThat(
            Runtime.version().feature() == 21,
            () -> System.out.println("This code block runs only if condition is true")
    );
    System.out.println("This code will run always");
}

The block (an Executable, so a lambda) runs only if the condition is true. Unlike the other two, a false condition does not skip the test: the block is skipped and the rest of the test still runs.

An assumption can also go in @BeforeAll: if it fails there, every test in the class is aborted.

Next: Assumptions decide from inside a test whether it runs. Chapter 11 decides from the outside which tests run: tagging tests and filtering by tag.

Check yourself ​

  1. Why is a plain if around the test logic not good enough?
  2. What is the difference between a failed and an aborted (skipped) test?
  3. What does assumeTrue do internally when the condition is false?
  4. When does a test using assumeFalse(x) run?
  5. With assumingThat(false, block), is the test skipped? What runs?
  6. How can you skip a test without the Assumptions class?
Answers
  1. When the condition is false the method just returns and the test is reported as passed, though nothing was tested.
  2. A failed test found a problem; an aborted test was not run because its preconditions did not hold, and is shown as skipped.
  3. It throws TestAbortedException, which the engine reports as aborted.
  4. Only when x is false.
  5. No: only the block is skipped; the rest of the test runs.
  6. Throw TestAbortedException yourself.