java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot Test webEnvironment

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的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文