SpringBoot Mock測試RequestBody引數幷包含其他引數介面
阿新 • • 發佈:2020-07-18
(當介面的引數用@RequestBody修飾,同時還有另外的引數的情況)
測試介面的時候,如果專案中請求經過閘道器,轉發到服務時,中間會將請求頭資料轉換成引數物件Subject。
格式如下:
@PutMapping("/demo/update") public String update(@Valid @RequestBody DemoRO demoRO, Subject subject) {
//...
return "success";
}
這時,如果使用mock測試,引數subject傳遞一直失敗,無法解析。
經過一番查詢,將實現瞭解析引數的 WebMvcConfigurer的實現類WebConfiguration加到Test的基類中載入,實現了正常的介面測試
@Configuration public class WebConfiguration implements WebMvcConfigurer { public WebConfiguration() { } //...
@Bean public FilterRegistrationBean<GlobalContextFilter> globalContextFilter() { FilterRegistrationBean<GlobalContextFilter> registrationBean = newFilterRegistrationBean(new GlobalContextFilter(), new ServletRegistrationBean[0]); registrationBean.addUrlPatterns(new String[]{"/*"}); registrationBean.setOrder(-2147483548); return registrationBean; }
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {//根據函式定義的引數型別匹配傳入的引數,並轉換成Subject物件 resolvers.add(new SubjectHandlerMethodArgumentResolver()); } //... }
請求引數與介面引數匹配類
public class SubjectHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { public SubjectHandlerMethodArgumentResolver() { } public boolean supportsParameter(MethodParameter parameter) { return Subject.class.isAssignableFrom(parameter.getParameterType()); } public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//如果介面引數滿足型別匹配(即 supportsParameter == true),則獲取由GlobalContext管理的儲存在ThreadLocal的subject return GlobalContext.getSubject().orElse((Object)null); } }
請求攔截器GlobalContextFilter
public class GlobalContextFilter extends OncePerRequestFilter { public GlobalContextFilter() { } protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { this.resolverSubject(request); try { filterChain.doFilter(request, response); } finally { this.clear(); } } private void clear() { GlobalContext.clear(); } //... private void resolverSubject(HttpServletRequest request) { if (NumberUtils.isNumber(request.getHeader("user-Id"))) { Long id = Long.valueOf(request.getHeader("user-Id")); Subject subject = Subject.builder().id(id).build(); //解析請求頭,並存入封裝了ThreadLocal的GlobalContext中 GlobalContext.setSubject(subject); } } }
測試基類
@RunWith(SpringRunner.class) @SpringBootTest(classes = DemoApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) @ContextConfiguration(classes = WebConfiguration.class, initializers= ConfigFileApplicationContextInitializer.class) @AutoConfigureMockMvc public class BaseTest { @Autowired protected MockMvc mockMvc; /** * web專案上下文 */ @Resource private WebApplicationContext webApplicationContext; @Resource private FilterRegistrationBean<GlobalContextFilter> globalContextFilter; @Before public void before() { //獲取mockmvc物件例項 mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) .addFilter(globalContextFilter.getFilter()) .build(); } }
Controller測試類
importstaticorg.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
importstaticorg.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
public class DemoControllerTest extends BaseTest { private final HttpHeaders httpHeaders = new HttpHeaders(); @Override public void before() { super.before(); httpHeaders.add("user-Id", "100001"); } @Test public void testUpdate() throws Exception { DemoRO updateRO = new DemoRO(); updateRO.setName("Demo111");this.mockMvc.perform( put("/demo/update") .contentType(MediaType.APPLICATION_JSON_UTF8) .headers(httpHeaders) .content(JSON.toJSONString(updateRO)) ).andDo(print()); }