skip to content

What is @DisabledInAotMode and what problem does it solve in Spring tests?

level: juniorimportance: should knowfreq 25%

answer

  1. org.springframework.test.context.aot
  2. skips test when AOT mode active
  3. frozen/pre-built context can't be mutated
  4. spring.aot.enabled=true
  5. since Spring 6.1

basics

~10 s

It is a Spring test annotation that skips a test when the app runs in AOT (ahead-of-time) mode. You put it on tests whose setup does not work with an AOT-optimized, pre-built application context.

solid answer

~40 s

@DisabledInAotMode (package org.springframework.test.context.aot, since Spring 6.1) marks a test class or method as incompatible with Spring AOT mode. AOT (ahead-of-time) processing builds and freezes the ApplicationContext at build time — typically for GraalVM native images — so the context's bean definitions cannot be changed at runtime. Tests that mutate the context (for example mocking a bean) break in that mode. The annotation does two things: it tells Spring's build-time test AOT processing to skip generating optimized artifacts for that context, and at runtime it disables the test whenever AOT mode is active (system property spring.aot.enabled=true). In ordinary JVM test runs (no AOT) the test runs normally, so it is a targeted opt-out, not a permanent disable.

code

java · 13 lines
java
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.aot.DisabledInAotMode;
import org.junit.jupiter.api.Test;

@SpringBootTest
@DisabledInAotMode // runs on the JVM, skipped when spring.aot.enabled=true
class CheckoutIntegrationTests {

    @Test
    void checkoutFlow() {
        // context-mutating setup that a frozen AOT context can't support
    }
}

go deeper

for a junior

Know it skips a test in AOT/native mode and lives in the Spring test API.

for a middle

Explain that a frozen AOT context can't be mutated and name a concrete trigger like mocking a bean.

for a senior

Distinguish the build-time skip from the runtime disable and mention AotDetector/spring.aot.enabled.

for a principal

Frame it as a coverage trade-off and discuss when to refactor a test to stay AOT-compatible instead.

## What it is `@DisabledInAotMode` is a Spring TestContext Framework annotation in package `org.springframework.test.context.aot`, introduced in **Spring Framework 6.1**. It declares that an annotated test is **disabled when Spring is running in AOT mode**. ## Background terms - **AOT (ahead-of-time) processing**: Spring can do at *build time* work it would normally do at *startup* — scanning, deciding bean definitions, and generating Java source that recreates the `ApplicationContext` without reflection or classpath scanning. This is the foundation for **GraalVM native images** and also speeds up JVM startup. The generated context is effectively **frozen**: its set of bean definitions is fixed and cannot be modified at runtime. - **AOT mode at runtime**: When you run against those generated artifacts, Spring sets/reads the system property `spring.aot.enabled=true`. Spring detects this via `org.springframework.aot.AotDetector.useGeneratedArtifacts()`. - **Test AOT processing**: Building a native test image runs a `process-test-aot` step. Spring refreshes each unique test `ApplicationContext` at build time to generate optimized code for it. ## The problem it solves Some tests deliberately **change the context**: they add or replace beans (mocking, spying, programmatic bean registration, custom `ApplicationContextInitializer`s that inject extra beans). A frozen AOT context cannot accept those changes, so such tests would fail or silently run against the real bean instead of the mock. `@DisabledInAotMode` cleanly excludes them. ## What it does (two effects) 1. **Build time**: Spring's test AOT generator **skips** the annotated class, so it does not try to produce AOT artifacts for that context (which would fail anyway). 2. **Runtime**: When `spring.aot.enabled=true`, the test is **disabled** (reported as skipped), similar to JUnit's `@Disabled` but conditional on AOT mode. Outside AOT mode (a normal `./gradlew test` on the JVM), the annotation has **no effect** — the test runs as usual. ## When to use Use it on a test that relies on `@MockitoBean`/`@MockitoSpyBean` (or the older Boot `@MockBean`/`@SpyBean`), or on any test that mutates the context, when you also build/run a native or AOT test suite. It is a surgical opt-out — prefer keeping most tests AOT-compatible. ## Gotcha It does not make the test 'pass' in native mode; it removes it from the AOT run. Your native-image coverage of that behavior is therefore lower, which is a conscious trade-off.

  • Does @DisabledInAotMode affect a normal JVM test run?
    No. It only takes effect when AOT mode is active (spring.aot.enabled=true) or during build-time test AOT processing. A plain ./gradlew test executes the test normally.

context