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?
answer
- Check the import: org.junit vs org.junit.jupiter.api
- private/static/abstract -> ignored
- Gradle useJUnitPlatform(); Surefire 2.22+
- runtime engine missing (api compiles, engine runs)
- class-name pattern *Test; @Disabled / failed assumption
basics
~20 sUsual 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 sThe 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// 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
Knows to check the @Test import and that the method shouldn't be private/static when a test won't run.
Lists the main causes — wrong import, bad signature, missing runtime engine, build config/name patterns — and can fix each.
Distinguishes API vs engine vs launcher dependencies, ties discovery to build-tool platform config, and separates silent non-discovery from @Disabled/assumption skips.
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