【问题标题】:Spring 3.2: Unit testing of @Scope("request") no longer worksSpring 3.2:@Scope("request") 的单元测试不再有效
【发布时间】:2013-12-19 06:05:13
【问题描述】:

在 Spring 3.1 中,我可以将具有 `@Scope("request") 的 Jax-RS 资源自动装配到我的单元测试中,前提是我包含以下 BeanFactoryPostProcessor:

@Component
public class MockRequestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

public void postProcessBeanFactory(
        ConfigurableListableBeanFactory beanFactory) throws BeansException {

    beanFactory.registerScope("request", new RequestScope());
    MockHttpServletRequest request = new MockHttpServletRequest();
    ServletRequestAttributes attributes = new ServletRequestAttributes(request);
    RequestContextHolder.setRequestAttributes(attributes);
}

}

在 Spring 3.2 中,第一个运行的测试方法可以工作,但所有后续测试方法都会得到

java.lang.IllegalStateException:未找到线程绑定请求:您是指实际 Web 请求之外的请求属性,还是在原始接收线程之外处理请求?如果您实际上是在 Web 请求中操作并且仍然收到此消息,则您的代码可能在 DispatcherServlet/DispatcherPortlet 之外运行:在这种情况下,请使用 RequestContextListener 或 RequestContextFilter 来公开当前请求。

我怎样才能让我的测试再次运行?

【问题讨论】:

  • 请添加您的测试类。

标签: java spring unit-testing jax-rs


【解决方案1】:

Spring 3.2 引入了ServletTestExecutionListener,它粗鲁地将自己注入到您的旧测试中。

它的javadoc:

TestExecutionListener 为 Spring TestContext Framework 加载的 WebApplicationContexts 提供模拟 Servlet API 支持。

具体来说,ServletTestExecutionListener 在测试实例准备期间和每个测试方法之前通过 Spring Web 的 RequestContextHolder 设置线程本地状态,并基于 WebApplicationContext 中存在的 MockServletContext 创建 MockHttpServletRequest、MockHttpServletResponse 和 ServletWebRequest。此侦听器还确保可以将 MockHttpServletResponse 和 ServletWebRequest 注入到测试实例中,并且一旦测试完成,此侦听器就会清理线程本地状态。

请注意,ServletTestExecutionListener 默认启用,但如果为当前测试加载的 ApplicationContext 不是 WebApplicationContext,则不会执行任何操作。

问题是最后一段是谎言。确实,除非您更改配置,否则此类不会开始帮助您,但无论如何它都会在每次测试后兴高采烈地重置请求。

可以通过将@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class }) 添加到测试类来禁用监听器。 (您可能需要根据需要编辑的实际侦听器集。)

或者,您可以设置 @WebAppConfiguration 并删除 MockRequestBeanFactoryPostProcessor 以及其他遗留解决方法,例如 MockServletContextAwareProcessor。

【讨论】:

  • 我会使用默认设置并放弃解决方法(需要维护的代码更少:))。很好的重置,您可能需要为此注册一个JIRA 错误/增强功能。
  • @M.Deinum 事情是,根据stackoverflow.com/questions/8878190/…,我用 ServletContexts 和单元测试做了一些花哨的事情。我需要设置资源路径,但@WebAppConfiguration.value 在编译时得到修复。所以我想我会继续使用我的自定义 ServletContextAwareProcessor。无论如何,当我手动运行 junit(通过 JUnitCore 以编程方式)时,内置的 SCAP 不起作用(@WAC 错误?),所以我别无选择。但似乎我可以一起使用 @WAC 和我的自定义 SCAP,同时跳过 RequestBeanFactoryPostProcessor
【解决方案2】:

BeanFactoryPostProcessor 有缺陷,它只运行一次,因此只有一个线程会有(不可重复使用的)MockHttpServletRequest

移动创建请求并将其存储在RequestContextHolder 中的代码应移至@Before 注释方法,而在@After 注释方法中,您应清除RequestContextHolder

@Before
public void init() {
    MockHttpServletRequest request = new MockHttpServletRequest();
    ServletRequestAttributes attributes = new ServletRequestAttributes(request);
    RequestContextHolder.setRequestAttributes(attributes);
}

@After
public void cleanUp() {
    RequestContextHolder.resetRequestAttributes();
}

您仍然需要BeanFactoryPostProcessor 来注册RequestScope

【讨论】:

  • 这不起作用,因为 Spring 在调用 @Before 方法之前自动连接我的测试类。
  • 您可以改为进行查找。您可以添加/尝试的另一件事是将 @WebAppConfiguration 注释添加到您的测试类(我假设您正在使用 Springs 测试支持来加载和自动装配)。这应该消除对BeanFactoryPostProcessor@Before/@After 方法的需要。
猜你喜欢
  • 1970-01-01
  • 2014-02-24
  • 1970-01-01
  • 2020-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多