使用自动装配的MockHttpServletRequest进行的多项测试无法正常工作?

时间:2014-03-28 12:04:00

标签: spring testng spring-test

我在一些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。

1 个答案:

答案 0 :(得分:4)

UPDATE :这已在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测试;这 not 适用于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)

这应该清除任何问题让您的测试套件快速运行。

此致

萨姆