Search code examples

@EnableAutoConfiguration doesn't work with @WebMvcTest. Why?

I discovered that I have to manually @Import autoconfiguration classes when using @WebMvcTest:

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.servlet.function.RouterFunction;
import org.springframework.web.servlet.function.ServerResponse;

import static;
import static;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(controllers = MyWebMvcTest.ComplimentingConfig.class)
public class MyWebMvcTest {
    MockMvc mockMvc;

    void test() throws Exception {

    static class ComplimentingConfig {
        public RouterFunction<ServerResponse> getRoute() {
            return route()
                    .GET("/get", http(""))

If I decide to import an @EnableAutoConfiguration-annotated configuration and thus include those imports implicitly, I get an exception as some required beans are not present in the context

@WebMvcTest(controllers = MyWebMvcTest.ComplimentingConfig.class)
public class MyWebMvcTest {

// ...

    static class ComplimentingConfig {
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type '' available

Why doesn't @EnableAutoConfiguration work with @WebMvcTest?

Java 17, Spring MVC 6.1.5, Spring Boot 3.2.4

Note. I used Spring Cloud Gateway MVC in the MRE above to necessitate additional @Imports. Had I used a plain RouterFuction (e.g. route().GET("/get", r -> ServerResponse.ok().build()).build()), the whole point would've been moot since all required beans would be implicitly provided by @WebMvcTest


  • First you need to understand between slice testing and integration testing.

    @WebMvcTest does not start full Spring application context. It is used for slice testing of web layer only. It scans for classes annotated with @Controller. To narrow down you can mention controller name like @WebMvcTest(XyzController.class). It is often accompanied with @MockBean in case you controller has reference to another class. It will not read your other configurations. Similarly, @DataJpaTest loads @Repository classes.

    Now you left with two options:

    1. @SpringBootTest - will look for main configuration class (one you annotated with @SpringBootApplication) and start Spring application context. This you can use for your integration testing. Here you defined either you want to use server or not

      @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
      class TestClass {}

      This will also start you server. If you don't want that you can use

      class TestClass {}
    2. @ContextConfiguration(classes = {XyzConfig.class}) - will load only mentioned configurations. This will be your slice testing.

      @ContextConfiguration(classes = {XyzConfig.class})
      class TestClass {}

    Now you can decide how you want to proceed.

    Why doesn't @EnableAutoConfiguration work with @WebMvcTest ?

    @WebMvcTest annotation will disable full auto-configuration and apply only configuration relevant to MVC tests, like I explained above. Even if you have explicitly mentioned auto-configuration, @WebMvcTest is overriding it. Read this