![](/img/trans.png)
[英]@Autowired and UnsatisfiedDependencyException in Spring integration test
[英]Autowired HttpServletRequest in Spring-test integration tests
我正在嘗試進行測試以涵蓋登錄功能。 Spring的版本是3.2.12。 我有一個會話bean,聲明為:
@Service
@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
public class ClientSessionServiceImpl implements ClientSessionService {
@Autowired
private HttpServletRequest request;
// This method is called during the login routine from the filter
public boolean checkUser() {
// I rely on request attributes here, which were set in the filter
}
這在服務器上運行時效果很好,但是當使用彈簧測試運行時,問題就出現了。 這是我的測試方法:
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).addFilter(springSecurityFilterChain).build();
mockMvc.perform(post(URL));
經過調試,我發現,當測試spring上下文啟動時,在ServletTestExecutionListener.setUpRequestContextIfNecessary中創建一個MockHttpServletRequest實例,MockHttpServletRequest request = new MockHttpServletRequest(mockServletContext); //讓我們調用這個實例A.這是我用的所有注入的實例
@Autowired
HttpServletRequest request;
然而,調用MockMvc.perform,創建另一個MockHttpServletRequest實例(讓我們稱之為實例B),它被傳遞給所有過濾器,servlet等。所以,基本上,我在請求中設置過濾器的屬性,不能在ClientSessionServiceImpl中讀取,因為在那里注入了不同的MockHttpServletRequest實例。
我花了很多時間在這上面,但仍然沒有找到解決方案。
PS我通過StackOverflow搜索,有類似標題的問題,但描述了與我的不同的問題,因為我不想傳遞HttpServletRequest作為參數,並且寧願讓它自動裝配,除非有充分的理由它。
因此,基本上,我在請求中的過濾器中設置的屬性無法在ClientSessionServiceImpl中讀取,因為MockHttpServletRequest的不同實例被注入其中。
這是關於Spring的RequestAttributes
何時填充在RequestContextHolder
的時間問題。 在生產中,我假設您正在配置RequestContextFilter
或RequestContextListener
。
無論如何,在測試中手動將RequestContextFilter
實例添加到過濾器鏈的前面將解決問題。
mockMvc = MockMvcBuilders
.webAppContextSetup(this.wac)
.addFilters(new RequestContextFilter(), testFilterChain)
.build();
請注意,這將成為Spring框架4.2的默認行為:代碼模擬RequestContextFilter
將直接在實施MockMvc
。 有關詳細信息,請參閱JIRA問題SPR-13217 。
另外,不支持配置由ServletTestExecutionListener
創建的MockHttpServletRequest
。 如果您使用的是MockMvc
,則需要通過RequestBuilders
配置RequestBuilders
請求。
但是,話雖如此,如果您有一個具體需要手動修改ServletTestExecutionListener
創建的模擬請求,然后重新使用MockMvc
,您可以在項目中創建以下類:
package org.springframework.test.web.servlet.request;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.HttpMethod;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* Patched version of {@link MockHttpServletRequestBuilder}.
*
* @author Sam Brannen
* @since 4.2
*/
public class PatchedMockHttpServletRequestBuilder extends MockHttpServletRequestBuilder {
public static MockHttpServletRequestBuilder get(String urlTemplate, Object... urlVariables) {
return new PatchedMockHttpServletRequestBuilder(HttpMethod.GET, urlTemplate, urlVariables);
}
public PatchedMockHttpServletRequestBuilder(HttpMethod httpMethod, String urlTemplate, Object... urlVariables) {
super(httpMethod, urlTemplate, urlVariables);
}
/**
* Create a {@link MockHttpServletRequest}.
* <p>If an instance of {@code MockHttpServletRequest} is available via
* the {@link RequestAttributes} bound to the current thread in
* {@link RequestContextHolder}, this method simply returns that instance.
* <p>Otherwise, this method creates a new {@code MockHttpServletRequest}
* based on the supplied {@link ServletContext}.
* <p>Can be overridden in subclasses.
* @see RequestContextHolder#getRequestAttributes()
* @see ServletRequestAttributes
*/
@Override
protected MockHttpServletRequest createServletRequest(ServletContext servletContext) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes instanceof ServletRequestAttributes) {
HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
if (request instanceof MockHttpServletRequest) {
return (MockHttpServletRequest) request;
}
}
return new MockHttpServletRequest(servletContext);
}
}
注意:它必須位於org.springframework.test.web.servlet.request
包中; 否則,它無法擴展所需的MockHttpServletRequestBuilder
。
然后,使用PatchedMockHttpServletRequestBuilder
的get()
方法而不是MockMvcRequestBuilders
,並且一切都應該按預期工作!
顯然,上面的例子重新實現了 get()
,但你可以自然地為post()
等做同樣的事情。
僅供參考:我最終可能會將上述修補版本的createServletRequest()
提交給Spring Framework 4.2.x(參見JIRA問題SPR-13211 )。
問候,
Sam( Spring TestContext Framework的作者 )
我有一個類似的問題,我在我的休息控制器中自動裝配了HttpServletRequest和HttpServletResponse
@Autowired protected HttpServletRequest httpRequest;
@Autowired protected HttpServletResponse httpResponse;
但是,當我嘗試使用下面的配置使用spring測試時,由於測試范圍無法自動裝配httpRequest
,測試失敗。
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("classpath:spring-config-unit-test.xml")
搜索web后的解決方案我將模擬請求和響應聲明為我的bean定義(單元測試)xml的第一行,如下所示。 希望這對某人有所幫助
<bean class="org.springframework.mock.web.MockHttpServletRequest" name="httpRequest" lazy-init="false" />
<bean class="org.springframework.mock.web.MockHttpServletResponse" name="httpResponse" lazy-init="false" />
您可以使用RequestPostProcessor來交換在perform內創建的請求。 您可以在測試中添加一個util方法,例如
private static RequestPostProcessor mockedRequest(final MockHttpServletRequest mockHttpServletRequest) {
return new RequestPostProcessor() {
@Override
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
return mockHttpServletRequest;
}
};
}
你會被通過將其應用於該后處理器with
方法
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).addFilter(springSecurityFilterChain).build();
mockMvc.perform(post(URL).with(mockedRequest(request)));
這里你傳遞給mockedRequest
方法的request
將是你原始的請求,包含你需要的屬性
試試這個配置:
@RunWith(SpringJUnit4ClassRunner.class)
public class MyTests extends AbstractContextControllerTests {
@Test
public void test() {
}
}
AbstractContextControllerTests的位置是這樣的:
@WebAppConfiguration
@ContextConfiguration(classes = {DispatcherConfig.class}, loader = AnnotationConfigWebContextLoader.class)
public class AbstractContextControllerTests {
@Autowired
protected WebApplicationContext wac;
}
而DispatherConfig是這樣的:
@Configuration
@EnableWebMvc
public class DispatcherConfig extends WebMvcConfigurerAdapter {
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.