SpringBoot Test的webEnvironment源码解读
作者:codecraft
这篇文章主要为大家介绍了SpringBoot Test的webEnvironment源码解读,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
序
本文主要研究一下SpringBootTest的webEnvironment
SpringBootTest
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @BootstrapWith(SpringBootTestContextBootstrapper.class) @ExtendWith({SpringExtension.class}) public @interface SpringBootTest { @AliasFor("properties") String[] value() default {}; @AliasFor("value") String[] properties() default {}; String[] args() default {}; Class<?>[] classes() default {}; WebEnvironment webEnvironment() default SpringBootTest.WebEnvironment.MOCK; }
SpringBootTest的webEnvironment默认为SpringBootTest.WebEnvironment.MOCK
WebEnvironment
/** * An enumeration web environment modes. */ enum WebEnvironment { /** * Creates a {@link WebApplicationContext} with a mock servlet environment if * servlet APIs are on the classpath, a {@link ReactiveWebApplicationContext} if * Spring WebFlux is on the classpath or a regular {@link ApplicationContext} * otherwise. */ MOCK(false), /** * Creates a web application context (reactive or servlet based) and sets a * {@code server.port=0} {@link Environment} property (which usually triggers * listening on a random port). Often used in conjunction with a * {@link LocalServerPort @LocalServerPort} injected field on the test. */ RANDOM_PORT(true), /** * Creates a (reactive) web application context without defining any * {@code server.port=0} {@link Environment} property. */ DEFINED_PORT(true), /** * Creates an {@link ApplicationContext} and sets * {@link SpringApplication#setWebApplicationType(WebApplicationType)} to * {@link WebApplicationType#NONE}. */ NONE(false); private final boolean embedded; WebEnvironment(boolean embedded) { this.embedded = embedded; } /** * Return if the environment uses an {@link ServletWebServerApplicationContext}. * @return if an {@link ServletWebServerApplicationContext} is used. */ public boolean isEmbedded() { return this.embedded; } }
WebEnvironment有四个枚举,分别是MOCK、RANDOM_PORT、DEFINED_PORT、NONE
SpringBootTestContextBootstrapper
spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextBootstrapper.java
public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstrapper { private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext" }; private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework." + "web.reactive.DispatcherHandler"; private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework.web.servlet.DispatcherServlet"; private static final String JERSEY_WEB_ENVIRONMENT_CLASS = "org.glassfish.jersey.server.ResourceConfig"; private static final String ACTIVATE_SERVLET_LISTENER = "org.springframework.test." + "context.web.ServletTestExecutionListener.activateListener"; private static final Log logger = LogFactory.getLog(SpringBootTestContextBootstrapper.class); @Override public TestContext buildTestContext() { TestContext context = super.buildTestContext(); verifyConfiguration(context.getTestClass()); WebEnvironment webEnvironment = getWebEnvironment(context.getTestClass()); if (webEnvironment == WebEnvironment.MOCK && deduceWebApplicationType() == WebApplicationType.SERVLET) { context.setAttribute(ACTIVATE_SERVLET_LISTENER, true); } else if (webEnvironment != null && webEnvironment.isEmbedded()) { context.setAttribute(ACTIVATE_SERVLET_LISTENER, false); } return context; } //...... }
SpringBootTestContextBootstrapper继承了DefaultTestContextBootstrapper,其buildTestContext方法会判断webEnvironment,然后决定ACTIVATE_SERVLET_LISTENER是设置为true还是false,在为MOCK的时候该值为true
ServletTestExecutionListener
spring-test/src/main/java/org/springframework/test/context/web/ServletTestExecutionListener.java
private boolean isActivated(TestContext testContext) { return Boolean.TRUE.equals(testContext.getAttribute(ACTIVATE_LISTENER)) || AnnotatedElementUtils.hasAnnotation(testContext.getTestClass(), WebAppConfiguration.class); } private void setUpRequestContextIfNecessary(TestContext testContext) { if (!isActivated(testContext) || alreadyPopulatedRequestContextHolder(testContext)) { return; } ApplicationContext context = testContext.getApplicationContext(); if (context instanceof WebApplicationContext) { WebApplicationContext wac = (WebApplicationContext) context; ServletContext servletContext = wac.getServletContext(); Assert.state(servletContext instanceof MockServletContext, () -> String.format( "The WebApplicationContext for test context %s must be configured with a MockServletContext.", testContext)); if (logger.isDebugEnabled()) { logger.debug(String.format( "Setting up MockHttpServletRequest, MockHttpServletResponse, ServletWebRequest, and RequestContextHolder for test context %s.", testContext)); } MockServletContext mockServletContext = (MockServletContext) servletContext; MockHttpServletRequest request = new MockHttpServletRequest(mockServletContext); request.setAttribute(CREATED_BY_THE_TESTCONTEXT_FRAMEWORK, Boolean.TRUE); MockHttpServletResponse response = new MockHttpServletResponse(); ServletWebRequest servletWebRequest = new ServletWebRequest(request, response); RequestContextHolder.setRequestAttributes(servletWebRequest); testContext.setAttribute(POPULATED_REQUEST_CONTEXT_HOLDER_ATTRIBUTE, Boolean.TRUE); testContext.setAttribute(RESET_REQUEST_CONTEXT_HOLDER_ATTRIBUTE, Boolean.TRUE); if (wac instanceof ConfigurableApplicationContext) { @SuppressWarnings("resource") ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) wac; ConfigurableListableBeanFactory bf = configurableApplicationContext.getBeanFactory(); bf.registerResolvableDependency(MockHttpServletResponse.class, response); bf.registerResolvableDependency(ServletWebRequest.class, servletWebRequest); } } }
ServletTestExecutionListener的isActivated会判断ACTIVATE_SERVLET_LISTENER是不是设置为true,或者testClass有标注@WebAppConfiguration; setUpRequestContextIfNecessary方法会调用isActivated来决定是否初始化MockHttpServletRequest等设置
小结
SpringBootTest的webEnvironment默认为SpringBootTest.WebEnvironment.MOCK,它会设置ACTIVATE_SERVLET_LISTENER是设置为true,即在ServletTestExecutionListener的isActivated为true,在setUpRequestContextIfNecessary方法会初始化MockHttpServletRequest、MockHttpServletResponse等。
以上就是SpringBootTest的webEnvironment源码解读的详细内容,更多关于SpringBootTest webEnvironment的资料请关注脚本之家其它相关文章!