2014-03-28 50 views
1

我在我的一些Spring測試中使用了@Autowired MockHttpServletRequest。 TestNG被用作測試框架。如果我在課堂上只有一種測試方法,這可以正常工作。但是,如果有多個測試方法,則只有第一次運行測試使用我的MockHttpServletRequest。讓我用一個例子:使用自動裝配的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。

回答

4

UPDATE:這已在Spring Framework 3.2.9,4.0.4和4.1中修復。詳情請參閱SPR-11626


好了,我的朋友......你在了Spring TestContext框架發現的錯誤。

此行爲的原因是ServletTestExecutionListener重置每個測試方法後的請求屬性,但DependencyInjectionTestExecutionListener不會在每個測試方法(默認情況下)之前重新注入依賴項。當執行第二種測試方法時,servletRequest字段仍然引用爲以前的測試方法創建的MockHttpServletRequest;而ServletTestExecutionListener爲每個測試方法創建一個新實例MockHttpServletRequest並將其設置爲請求屬性。因此,注入的請求和存儲在RequestContextHolder中的請求只與TestNG中執行的第一個測試方法相同。

由於我是這段代碼的作者,所以我必須親自道歉,但是......我會確保它儘快得到修復。有關修復狀態的詳細信息,請參閱SPR-11626。 ;)

注意:此錯誤僅適用於TestNG測試;這個不是適用於JUnit測試。

作爲解決方法,您可以使用@DirtiesContext(或用@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)註釋您的測試類)來註釋受影響的測試方法。這將允許您的測試按照您的預期通過。

使用@DirtiesContext將使Spring在每種測試方法後關閉您的測試ApplicationContext,這可能會對測試速度產生負面影響;不過,從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) 

這應該澄清任何問題保持你的測試套件快速運行。

問候,

山姆