【问题标题】:Multiple tests with autowired MockHttpServletRequest not working?自动装配的 MockHttpServletRequest 的多个测试不起作用?
【发布时间】:2014-03-28 12:04:00
【问题描述】:

我在一些 Spring 测试中使用了@Autowired MockHttpServletRequest。 TestNG 用作测试框架。如果我在课堂上只有一种测试方法,那效果很好。但是,如果有多个测试方法,只有第一次运行测试使用我的 MockHttpServletRequest。我举个例子来说明:

@WebAppConfiguration
@ContextConfiguration({"classpath:applicationContext.xml"})
public class FooTest extends AbstractTestNGSpringContextTests {

    @Autowired
    private MockHttpServletRequest servletRequest;

    @Test
    public void test1() {
        assertEquals(((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest(), servletRequest);
    }

    @Test
    public void test2() {
        assertEquals(((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest(), servletRequest);
    }

}

在本例中,test1() 通过,但test2() 失败!如果您单独运行测试方法,它们都会通过。如果一起运行,为什么一个测试会失败?

我试图挖掘代码,在测试方法运行后似乎对请求属性进行了某种重置,但我没有找到关闭它的方法。我的 Spring 版本是 3.2.8.RELEASE。

【问题讨论】:

    标签: spring testng spring-test


    【解决方案1】:

    更新:这已在 Spring Framework 3.2.9、4.0.4 和 4.1 中得到修复。详情请见SPR-11626


    好吧,我的朋友……你在 Spring TestContext Framework 中发现了一个错误。

    这种行为的原因是ServletTestExecutionListener 在每个测试方法之后重置请求属性,但DependencyInjectionTestExecutionListener 不会在每个测试方法之前重新注入依赖项(默认情况下)。执行第二个测试方法时,servletRequest 字段仍然引用为前一个测试方法创建的MockHttpServletRequest;而ServletTestExecutionListener 为每个测试方法创建一个MockHttpServletRequest 的新实例,并将其设置在请求属性中。因此,注入的请求和存储在RequestContextHolder 中的请求仅对于在TestNG 中执行的第一个测试方法是相同的。

    由于我是这段代码的作者,我必须亲自道歉,但是……我会确保它尽快得到修复。有关修复状态的详细信息,请参阅SPR-11626。 ;)

    注意:此错误仅适用于 TestNG 测试;这适用于 JUnit 测试。

    作为一种解决方法,您可以使用@DirtiesContext 注释受影响的测试方法(或使用@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) 注释您的测试类)。这将使您的测试按预期通过。

    @DirtiesContext 的使用会使 Spring 在每个测试方法之后关闭您的测试 ApplicationContext,这可能会对您的测试速度产生负面影响;但是,从 Spring 3.2.8 和 4.0.3 开始,这是唯一的非自定义解决方案。

    话虽如此,以下是一种更有效的解决方法。只需在您的项目中定义此自定义 TestExecutionListener

    public class AlwaysReinjectDependenciesTestExecutionListener extends AbstractTestExecutionListener {
    
        public void afterTestMethod(TestContext testContext) throws Exception {
            testContext.setAttribute(DependencyInjectionTestExecutionListener.REINJECT_DEPENDENCIES_ATTRIBUTE, Boolean.TRUE);
        }
    
    }
    

    然后像这样注释您的测试类:

    @TestExecutionListeners(AlwaysReinjectDependenciesTestExecutionListener.class)
    

    这应该可以解决所有问题保持您的测试套件快速运行。

    问候,

    山姆

    【讨论】:

      猜你喜欢
      • 2018-12-01
      • 2014-07-31
      • 1970-01-01
      • 1970-01-01
      • 2017-11-30
      • 2014-09-01
      • 2017-01-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多