skip to content

When is WebEnvironment.NONE the right choice, and how does it differ from a plain non-web @SpringBootTest?

level: seniorimportance: should knowfreq 40%

answer

  1. NONE = full context, zero web
  2. No servlet context, no server, no port
  3. Services/repos/schedulers/listeners
  4. Heavier than a slice, but real full graph
  5. Same-thread → @Transactional rolls back

basics

~20 s

Use NONE when you want the full application context but no web layer — for testing services, repositories, or scheduled/messaging beans. It loads via SpringApplication with no servlet context, no embedded server, and no port.

solid answer

~40 s

WebEnvironment.NONE boots the entire ApplicationContext through SpringApplication but explicitly disables the web environment: it creates a non-web (plain) context, so there's no servlet context, no embedded Tomcat, and no listening port. You choose it when the web layer is irrelevant to what you're testing — wiring of `@Service`/`@Repository` beans, JPA persistence, event listeners, `@Scheduled`/messaging components — but you still want the real, fully wired context (as opposed to a sliced or hand-built one). Compared to slice tests (`@DataJpaTest`, plain `@SpringBootTest` with `@WebMvcTest`), NONE still loads the *whole* context, so it's heavier but more representative. It differs from RANDOM_PORT/DEFINED_PORT in that no server starts, and from MOCK in that not even a mock servlet environment is created. TestRestTemplate and MockMvc don't apply here — there's nothing HTTP to call.

code

java · 11 lines
java
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
class UserServiceIntegrationTest {
    @Autowired UserService userService; // real bean graph, no web layer

    @Test
    @Transactional // rolls back fine — runs on the test thread
    void registersUser() {
        var id = userService.register("[email protected]");
        assertThat(userService.find(id).email()).isEqualTo("[email protected]");
    }
}

go deeper

for a junior

Knows NONE means no server/port.

for a middle

Uses NONE for service/repository tests and knows web beans are absent.

for a senior

Contrasts NONE with MOCK, real-server modes, and slices; picks the leanest adequate option.

for a principal

Sets guidance on full-context vs slice vs web modes to keep the suite fast and representative.

## What NONE does `@SpringBootTest(webEnvironment = WebEnvironment.NONE)` runs `SpringApplication` with the web environment turned **off**. Concretely: - A **non-web `ApplicationContext`** is created (not a `WebApplicationContext`). - **No servlet context**, **no embedded server**, **no port**. - All your normal beans still load and wire up: services, repositories, configuration, `@Scheduled` tasks, event listeners, messaging consumers, etc. ## When to reach for it - You want to test **backend logic through the real bean graph** — e.g. a `@Service` that calls a repository, transaction boundaries, domain events — without any HTTP concern. - You're testing components that have **nothing to do with the web tier** (batch jobs, schedulers, Kafka/JMS listeners, startup runners). - You want the **full context** rather than a slice, because the interaction under test spans several modules that a slice annotation wouldn't load. ## How it contrasts with the alternatives - **vs MOCK:** MOCK still builds a *mock* servlet environment (`WebApplicationContext` + `MockServletContext`) so MockMvc works. NONE builds no web environment at all — MockMvc is not available. - **vs RANDOM_PORT/DEFINED_PORT:** those start a **real server**; NONE starts **none**. So `@LocalServerPort` and `TestRestTemplate` are irrelevant under NONE. - **vs slice tests** (`@DataJpaTest`, `@WebMvcTest`, `@JsonTest`): slices load only a **subset** of the context and are faster; NONE loads the **entire** context (heavier, but exercises real cross-cutting wiring). Use a slice when you can; use NONE + `@SpringBootTest` when you truly need the full graph but not the web layer. ## Practical notes / gotchas - If your app is a web app but a test doesn't touch HTTP, NONE avoids the cost and side effects of starting a server (faster, no port to clash). - Because there's no web context, **web-specific beans** (controllers, filters, `MockMvc`, `TestRestTemplate`) won't be present/auto-configured — don't inject them. - Same-thread execution means `@Transactional` on the test **rolls back normally** (unlike real-server modes), which is convenient for repository/service tests. - If you accidentally leave the default (MOCK) for a pure service test, you needlessly build a web context; NONE is the leaner, more honest choice.

  • Why choose @SpringBootTest(webEnvironment=NONE) over a slice like @DataJpaTest?
    NONE loads the full context, so it's right when the behavior spans many beans/modules that a slice wouldn't wire up. A slice is lighter/faster but only loads its subset; prefer the slice when it covers what you need.
  • Can you use MockMvc under NONE?
    No. NONE creates no web environment, so there's no DispatcherServlet/servlet context for MockMvc. Use MOCK (with @AutoConfigureMockMvc) if you need MockMvc.

saying these in an interview costs you the question

  • Thinking NONE still lets you use MockMvc or TestRestTemplate
  • Confusing NONE (no context web layer) with a slice test (partial context)
  • Believing NONE skips loading non-web beans — it loads the full context

context