簡體   English   中英

在Spring-test集成測試中自動連接HttpServletRequest

[英]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的時間問題。 在生產中,我假設您正在配置RequestContextFilterRequestContextListener

無論如何,在測試中手動將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

然后,使用PatchedMockHttpServletRequestBuilderget()方法而不是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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM