代码之家  ›  专栏  ›  技术社区  ›  holmis83

自动连线MockHttpServletRequest的多个测试不工作?

  •  1
  • holmis83  · 技术社区  · 10 年前

    我使用 @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 回复  |  直到 10 年前
        1
  •  4
  •   Sam Brannen    10 年前

    更新 :这已在Spring Framework 3.2.9、4.0.4和4.1中修复。看见 SPR-11626 详细信息。


    我的朋友。。。您在 Spring TestContext框架 .

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

    既然我是这段代码的作者,我必须亲自道歉,但是。。。我会确保尽快修复。看见 第1166页 有关修复状态的详细信息。;)

    笔记 :此错误仅适用于TestNG测试;这是真的 适用于JUnit测试。

    作为解决方案,您可以使用 @DirtiesContext (或使用 @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) ). 这将使您的测试按预期通过。

    使用 @污垢上下文 将使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)
    

    这应该可以解决任何问题 保持测试套件快速运行。

    当做

    山姆