Я обнаружил, что мне приходится вручную @Import
классы автоконфигурации при использовании @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 org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;
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)
@Import({GatewayServerMvcAutoConfiguration.class,
SslAutoConfiguration.class,
RestClientAutoConfiguration.class})
public class MyWebMvcTest {
@Autowired
MockMvc mockMvc;
@Test
void test() throws Exception {
mockMvc.perform(get("/get"))
.andExpect(status().isOk());
}
@Configuration
static class ComplimentingConfig {
@Bean
public RouterFunction<ServerResponse> getRoute() {
return route()
.GET("/get", http("https://httpbin.org/status/200"))
.build();
}
}
}
Если я решу импортировать конфигурацию с аннотацией @EnableAutoConfiguration
и, таким образом, неявно включить этот импорт, я получу исключение, поскольку некоторые необходимые bean-компоненты отсутствуют в контексте.
@WebMvcTest(controllers = MyWebMvcTest.ComplimentingConfig.class)
@Import(MyWebMvcTest.ComplimentingConfig.class)
public class MyWebMvcTest {
// ...
@Configuration
@EnableAutoConfiguration
static class ComplimentingConfig {
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.cloud.gateway.server.mvc.handler.ProxyExchangeHandlerFunction' available
Почему @EnableAutoConfiguration
не работает с @WebMvcTest
?
Java 17, Spring MVC 6.1.5, Spring Boot 3.2.4
Примечание. Я использовал Spring Cloud Gateway MVC в MRE выше, чтобы потребовать дополнительных @Import
. Если бы я использовал простой RouterFuction
(например, route().GET("/get", r -> ServerResponse.ok().build()).build()
), весь вопрос был бы спорным, поскольку все необходимые компоненты были бы неявно предоставлены @WebMvcTest
Насколько я понимаю, как работает Spring MVC. Spring пытается упростить и больше сосредотачивается на конкретном тестовом примере. Я имею в виду, что @WebMvcTest
работает только в ограниченном контексте приложения, чтобы уменьшить количество несвязанных компонентов.
О Spring Cloud Gateway, который использует RouterFunction
, использует автоконфигурацию для настройки необходимых компонентов, тогда как @WebMvcTest
фокусируется только на Mvc и не включает все bean-компоненты, связанные со шлюзом.
Не слишком уверен в этом, но именно это я понял, когда в последний раз возился с этой темой.
Сначала вам нужно понять, что такое срезовое тестирование и интеграционное тестирование.
@WebMvcTest
не запускает полный контекст приложения Spring. Он используется только для срезового тестирования веб-слоя. Он сканирует классы, помеченные знаком @Controller
. Чтобы сузить список, вы можете указать имя контроллера, например @WebMvcTest(XyzController.class)
. Он часто сопровождается @MockBean
, если ваш контроллер имеет ссылку на другой класс. Он не будет читать другие ваши конфигурации. Аналогично @DataJpaTest
загружает @Repository
занятия.
Теперь у вас осталось два варианта:
@SpringBootTest
— будет искать основной класс конфигурации (тот, который вы отметили @SpringBootApplication
) и запускать контекст приложения Spring. Это вы можете использовать для своего интеграционного тестирования. Здесь вы определили, хотите ли вы использовать сервер или нет.
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class TestClass {}
Это также запустит ваш сервер. Если вы этого не хотите, вы можете использовать
@SpringBootTest
@AutoConfigureMockMvc
class TestClass {}
@ContextConfiguration(classes = {XyzConfig.class})
— будут загружены только указанные конфигурации. Это будет ваше срезовое тестирование.
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {XyzConfig.class})
class TestClass {}
Теперь вы можете решить, как вы хотите действовать.
Почему @EnableAutoConfiguration не работает с @WebMvcTest?
@WebMvcTest
аннотация отключит полную автоматическую настройку и будет применять только конфигурацию, соответствующую тестам MVC, как я объяснил выше. Даже если вы явно упомянули автоконфигурацию, @WebMvcTest
отменяет ее. Прочтите это
Обновил свой ответ. Аннотация @WebMvcTest отключит полную автоматическую настройку и применит только конфигурацию, соответствующую тестам MVC, как я объяснил в своем ответе. Надеюсь, теперь все ясно.
Спасибо! Хотя я все это знаю. С другой стороны, я не знаю, почему явная
@Import
работа работает, а извлечение@EnableAutoConfiguration
-аннотированной конфигурации — нет (хотя оба, похоже, делают одно и то же)