java时间怎么mock掉_微服务中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 {

@Autowired

private HelloService helloService;

@PostMapping("/user/profile")

public ProfileResp UserProfile(ProfileReq req) {

return helloService.profile(req);

}

}

HelloService.java

@Service

public class HelloService {

@Autowired

private 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 {

@Autowired

private WebApplicationContext webApplicationContext;

@Autowired

private ObjectMapper objectMapper;

@Autowired

private MockMvc mockMvc;

@Mock

private UserApiClient userApiClient;

@BeforeEach

void mockFeignClient() throws NoSuchFieldException, IllegalAccessException {

HelloService helloService = webApplicationContext.getBean(HelloService.class);

Field fieldUserApiClient = HelloService.class.getDeclaredField("userApiClient");

fieldUserApiClient.setAccessible(true);

fieldUserApiClient.set(helloService, this.userApiClient);

}

@Test

void 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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值