Spring GenericWebApplicationContext 被加载,尽管 web 应用程序类型:NONE

Spring GenericWebApplicationContext gets loaded despite web-application-type: NONE

在我的 Spring 2.5 web 应用程序中,我试图编写一个测试,在其中禁用它是一个 web 应用程序这一事实:这是因为该应用程序还包含一些使用的计划任务一些 Oauth2 组件调用其他服务。

这些 Oauth2 组件的行为有所不同,具体取决于它们是否从 Servlet 上下文中触发(参见 official doc)。

现在,当我执行 @SpringBootTest 时,我看到了:

[org.springframework.context.support.AbstractApplicationContext] [main] [629] [DEBUG] Refreshing org.springframework.web.context.support.GenericWebApplicationContext        

我想禁用它,所以在我的 application.yml 中,我设置了 spring.main.web-application-type=NONE ,但它不起作用我仍然看到 WebApplicationContext(我还设置了 属性到一个错误的值,以确保它被考虑在内并且失败了:它是,所以我知道我的 applicaion.yml 文件被读取并被我测试考虑了)。

我希望一旦我能够禁用它,那么 ServletTestExecutionListener 不会被触发,也不会创建 MockServletContext

@SpringBootTest 使用 WebEnvironment.MOCK 作为 webEnvironment.

的默认配置值

如果您不想针对 WebApplicationContext 进行测试,您可以覆盖此值:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)

因为我们无法轻松启用我们需要的自动配置,当我们设置 webEnvironment = SpringBootTest.WebEnvironment.NONE 时被禁用(参见 中的评论),我们必须采取不同的方法。

我们不能轻易阻止 ServletTestExecutionListener 被调用,但我们可以添加我们自己的 TestExecutionListener,它将在测试上下文中重置我们需要的部分。幸运的是,我们添加的侦听器在 ServletTestExecutionListener 之后被调用,因此确实可以“撤消”我们需要的东西。

import org.springframework.test.context.TestContext;
import org.springframework.test.context.support.AbstractTestExecutionListener;
import org.springframework.web.context.request.RequestContextHolder;

/**
 * It's difficult to test a scheduled task that is part of a web application : out of the box, Spring Boot will set up a mock servlet context
 * through {@link org.springframework.test.context.web.ServletTestExecutionListener}. But in production, the servlet context is null and HTTP calls through {@code WebClient} may fail
 * if it's not configured correctly - see <a href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/oauth2/client/AuthorizedClientServiceOAuth2AuthorizedClientManager.html">the doc</a>
 * for an example of how it should typically configured.
 * If not configured correctly, WebClient calls may fail at runtime, and we may not be able to reproduce easily in a test, because servletRequest is no tnull like in prod, but set to a mock servlet context.
 *
 * Using {@code ResettingServletContextToNullListener}, we reset to null the servletContext that was initialized in {@link org.springframework.test.context.web.ServletTestExecutionListener}, and create a context that is much closer to what it is at runtime in production
 */
public class ResettingServletContextToNullListener extends AbstractTestExecutionListener {

  @Override
  public void beforeTestMethod(TestContext testContext) {
    System.out.println("resetting servletContext to null, like it is at runtime when a scheduled task is triggered..");
    RequestContextHolder.setRequestAttributes(null);
  }

}

然后我们可以简单地在我们的测试中添加这个:

@SpringBootTest
@TestExecutionListeners(value = ResettingServletContextToNullListener.class, mergeMode = MergeMode.MERGE_WITH_DEFAULTS)
class MyScheduledTaskIntegrationTest {

...

}

使用该设置,计划任务的测试上下文类似于它在生产环境中运行时的情况,即 servletRequest 为空:然后我们可以调整我们的 Oauth2 配置,以便它在运行时不会失败案例.