微服务中mock掉feign Client进行restful单元测试
今天分享一个在微服务中restful接口的单元测试例子,主要涉及三方面:内部调用的mock、接口DTO的序列化和反序列化、用MockMvc加速单元测试用例执行。
-
单元测试要求不依赖外部服务,这样才能够方便的支持在各种环境下执行,特别是CI环境。但是在微服务开发中最常见的依赖就是服务间的调用。好在有Mockito,我们可以方便的实现各种stub来mock掉feign client的调用。
-
为了尽可能的测试到微服务的调用过程,我们还需要模拟DTO的序列号和反序列化过程。在一个restful接口的单元测试中序列化过程如下,保证请求和响应结构都会经历序列化和反序列化过程:
请求数据序列化-->请求数据发序列化响应数据序列化-->响应数据反序列化 -
MockMvc可以不启动http服务完成模拟rest的服务处理请求。因此一般使用MockMvc模拟restful服务来加速单元测试的执行。
HelloController.java
@RestController
public class HelloController {@Autowiredprivate HelloService helloService;@PostMapping("/user/profile")public ProfileResp UserProfile(ProfileReq req) {return helloService.profile(req);}
}
HelloService.java
@Service
public class HelloService {@Autowiredprivate UserApiClient userApiClient;public ProfileResp profile(ProfileReq req) {return userApiClient.profile(req);}
}
UserApiClient.java
@FeignClient(name = "UserApiClient",path = "/user")
public interface UserApiClient {@PostMapping("/profile")ProfileResp profile(ProfileReq req);
}
上面是controller、service和feign client,下面是测试类,通过AutoConfigureMockMvc注解自动配置MockMvc,会加载当前包的所有controller到MockMvc内。通过注入WebApplicationContext然后用其来获取容器中的bean,方便再单元测试开始前用反射将feignClient的字段替换成mock对象。再单元测试内使用Mockito.when(userApiClient.profile(Mockito.any())).thenReturn(new ProfileResp("0000","success"));插入stub使替换掉的userApiClient再调用profile接口时返回我们需要的结果。
objectMapper则是用来模拟spring web的jackson序列化和反序列化操作。
完整代码如下:
DemoApplicationTests.java
@SpringBootTest
@AutoConfigureMockMvc
class DemoApplicationTests {@Autowiredprivate WebApplicationContext webApplicationContext;@Autowiredprivate ObjectMapper objectMapper;@Autowiredprivate MockMvc mockMvc;@Mockprivate UserApiClient userApiClient;@BeforeEachvoid mockFeignClient() throws NoSuchFieldException, IllegalAccessException {HelloService helloService = webApplicationContext.getBean(HelloService.class);Field fieldUserApiClient = HelloService.class.getDeclaredField("userApiClient");fieldUserApiClient.setAccessible(true);fieldUserApiClient.set(helloService, this.userApiClient);}@Testvoid userProfile() throws Exception {Mockito.when(userApiClient.profile(Mockito.any())).thenReturn(new ProfileResp("0000","success"));ProfileReq req = ProfileReq.builder().uid("1111").build();byte[] data = mockMvc.perform(MockMvcRequestBuilders.post("/user/profile").content(objectMapper.writeValueAsBytes(req))).andExpect(MockMvcResultMatchers.status().isOk()).andReturn().getResponse().getContentAsByteArray();ProfileResp resp = objectMapper.readValue(data, ProfileResp.class);Assertions.assertNotNull(resp);Assertions.assertEquals("0000", resp.getCode());}
}
提示:本文为了方便阅读省略了import等代码。本例子使用的是junit5。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
