skip to content

A developer writes a method marked @Test but it never runs — no pass, no fail, no error. What are the common reasons a @Test method is silently not discovered or executed by JUnit 5?

level: middleimportance: should knowfreq 55%

answer

  1. Check the import: org.junit vs org.junit.jupiter.api
  2. private/static/abstract -> ignored
  3. Gradle useJUnitPlatform(); Surefire 2.22+
  4. runtime engine missing (api compiles, engine runs)
  5. class-name pattern *Test; @Disabled / failed assumption

basics

~20 s

Usual causes: importing JUnit 4's org.junit.Test instead of org.junit.jupiter.api.Test, the method being private or static, the test class or method matching no naming/include pattern in the build config, or the JUnit Platform/Jupiter engine not being on the runtime classpath.

solid answer

~40 s

The most frequent cause is the wrong import: org.junit.Test (JUnit 4) instead of org.junit.jupiter.api.Test (Jupiter). With the JUnit 4 annotation and no Vintage engine, nothing runs it. Other causes: the method is private, static, or abstract, so Jupiter skips it; the build tool's test include/exclude patterns or class-name conventions don't match the file; the JUnit 5 dependencies (junit-jupiter-api at compile time, the junit-jupiter-engine plus junit-platform-launcher at runtime) are missing, so there's no engine to discover it; or the test runner is still configured for JUnit 4 (e.g. Gradle without useJUnitPlatform(), or Surefire too old). A @Disabled annotation or a class-level assumption can also suppress it. The fix is to verify the import, visibility, runtime engine, and build configuration.

code

java · 18 lines
java
// BROKEN: nothing runs
import org.junit.Test;                 // (1) JUnit 4 import

class BrokenTest {
    @Test
    private static void check() {}      // (2) private + static -> ignored
}

// FIXED
import org.junit.jupiter.api.Test;     // correct Jupiter import
import static org.junit.jupiter.api.Assertions.assertEquals;

class WorkingTest {
    @Test
    void check() {                      // package-private instance, void
        assertEquals(2, 1 + 1);
    }
}

go deeper

for a junior

Knows to check the @Test import and that the method shouldn't be private/static when a test won't run.

for a middle

Lists the main causes — wrong import, bad signature, missing runtime engine, build config/name patterns — and can fix each.

for a senior

Distinguishes API vs engine vs launcher dependencies, ties discovery to build-tool platform config, and separates silent non-discovery from @Disabled/assumption skips.

for a principal

Can audit a project's test dependency graph and CI config to prevent whole suites silently not running, and set conventions (naming, platform config, dependency BOM) to make it robust.

## The symptom A `@Test` method that produces **no result at all** — not green, not red, not errored — was **never discovered or executed**. This is different from a *failing* test. The framework simply didn't see it as a runnable test. Here are the usual culprits. ## 1. Wrong `@Test` import (the #1 cause) ```java import org.junit.Test; // JUnit 4 — WRONG for Jupiter // vs import org.junit.jupiter.api.Test; // JUnit 5 — correct ``` The Jupiter engine only recognizes **its own** `@Test`. If you import JUnit 4's annotation and the **Vintage** engine isn't present, nothing runs the method. Because both compile, the IDE may not warn you. ## 2. Illegal method signature Jupiter ignores a method if it is **`private`**, **`static`**, or **`abstract`**. A common slip: ```java @Test private void shouldWork() { ... } // ignored — must not be private ``` (Returning non-`void` may also cause it to be skipped/flagged.) Make it a non-static, non-private instance method. ## 3. Build-tool discovery configuration - **Gradle:** the `test` task must call `useJUnitPlatform()`. Without it, Gradle uses the old JUnit 4 runner and ignores Jupiter tests. - **Maven:** the **Surefire** plugin must be new enough (2.22+) to support the JUnit Platform; older versions don't discover Jupiter tests. - **Include/exclude patterns:** build tools filter test classes by name (commonly `*Test`, `Test*`, `*Tests`). If your class is `MyChecks` and the pattern requires a `Test` suffix, it's never scanned. ## 4. Missing runtime engine / launcher on the classpath JUnit 5 splits dependencies: - `junit-jupiter-api` — compile-time, gives you `@Test` and assertions. - `junit-jupiter-engine` — **runtime**, the engine that actually discovers and runs them. - `junit-platform-launcher` — the launcher the tool calls. If you have only the **API** on the classpath (compiles fine) but **no engine** at runtime, discovery finds **zero** Jupiter tests. The aggregator `junit-jupiter` artifact pulls the right pieces together. ## 5. Deliberately or accidentally suppressed - **`@Disabled`** on the method or class skips it (it shows as *skipped*, not silent, but is easy to overlook). - A **failing assumption** at class or `@BeforeEach` level (`assumeTrue(false)`) aborts tests — they show as aborted/skipped. - The class itself isn't recognized as a test container (e.g. it's an abstract base with no concrete subclass run). ## How to diagnose 1. Check the **import** first — flip to `org.junit.jupiter.api.Test`. 2. Make the method **non-private, non-static**, returning `void`. 3. Confirm the build is on the **Platform** (`useJUnitPlatform()` / recent Surefire) and the **runtime engine** dependency is present. 4. Check **class-name patterns** and `@Disabled`/assumptions. Most "my test won't run" reports are #1 (import) or #4 (no runtime engine).

  • You added junit-jupiter-api and the test compiles, but zero tests run. What's the most likely missing piece?
    The runtime engine: junit-jupiter-engine (and junit-platform-launcher) must be on the test runtime classpath. The API gives you the annotations to compile against, but without an engine there is nothing to discover and execute the tests.
  • In Gradle, what single configuration is most commonly missing when Jupiter tests don't run?
    tasks.test { useJUnitPlatform() }. Without it, Gradle defaults to the JUnit 4 runner and ignores Jupiter @Test methods.

saying these in an interview costs you the question

  • Assuming a silently-skipped test is passing — no result means it never ran
  • Believing the API artifact alone is enough at runtime — you also need the engine
  • Forgetting useJUnitPlatform() in Gradle and blaming the test code
  • Marking a test private and expecting JUnit to call it

context