写点什么

SpringBoot 系列(6)- 测试

用户头像
引花眠
关注
发布于: 2020 年 12 月 14 日

测试

我想大家对于测试都不陌生,常见的测试,有各种不同的分类,比如单元测试、集成测试、系统测试等等。 一般由程序员自己做的测试有单元测试与系统测试。 单元测试,不同的人对于单元的含义有不同的理解,有的人认为只有函数是一个单元,有的人认为一个类是一个单元, 不过大家都认为单元测试都应该很快,而如果要达成这种效果,就应该避免操作数据库,访问文件系统或者法送真实的网络请求, 所以一般情况下应该 mock 测试中的依赖。


spring 单元测试

我们使用 spring 进行单元测试时,可以只注入需要测试的类,将其他需要测试的类使用 mock 实现。 如果我们要对如下的代码进行测试


@Servicepublic class OrderService {
@Autowired private OrdersRepository ordersRepository;
public Long placeOrder(Order order) { return ordersRepository.createOrder(order); }}
复制代码


测试代码可以如下


@RunWith(SpringRunner.class)@SpringBootTestclass OrderServiceTest {
@Autowired private OrderAppService orderAppService;

@MockBean private OrdersRepository ordersRepository;
@BeforeEach void setUp() throws Exception { }
@Test void testPlaceOrder() { Order order = new Order(); //mock ordersRepository ,让所有的保存都返回2 Mockito.when(ordersRepository.createOrder(ArgumentMatchers.any(Order.class))) .thenReturn(2L); long result = orderAppService.placeOrder(order); assertEquals(result, 2L); }
}
复制代码


@MockBean 声明这是一个模拟的 bean。在进行单元测试时,需要将测试目标的所有依赖 bean 声明为模拟的 bean,这些模拟的 bean 将被注入测试目标 bean。 使用 Mockito.when 对 ordersRepository.createOrder()方法进行打桩,设定当方法被调用时,直接返回我们预设的数据。


测试 web 应用程序

如果要测试 controller 等 web 组建,一种方式是直接将程序发布到容器中进行测试,另一种方式是使用 mock 模拟测试 在 spring 中可以通过 Mock MVC,在一个近似真实的模拟 Servlet 容器里测试控制器。


要在测试中设置 Mock MVC,可以用 MockMvcBuilders,它提供了两个静态方法可以是实现:


  1. standaloneSetup():构建一个 Mock MVC,提供一个或多个手工初始化并注入我们要测试的控制器(需要手工初始化并注入要测试的控制器)

  2. webAppContextSetup():使用 Spring 应用程序的上下文来构建 Mock MVC,该上下文可以包含一个或多个配置好的控制器(基于 WebApplicationContext 的实例,由 Spring 加载控制器和其依赖)


准备测试代码

以下是我们要测试的代码


@RestController@RequestMapping(value = "orders")public class OrdersController {
@Autowired private OrderAppService orderService;
@PostMapping("createOrder") public ApiResult createOrder(OrderDto orderDto) { Order order = OrderDto.toOrder(orderDto); Long orderId = orderService.placeOrder(order); return ApiResult.success(orderId); }}
复制代码


返回的类型是


@Datapublic class ApiResult {
private Integer code; private String message; private Object data;}
复制代码


基于 standaloneSetup

@RunWith(SpringRunner.class)@SpringBootTestclass OrdersControllerStTest {
@MockBean private OrderAppService orderAppService;
@InjectMocks private OrdersController ordersController;
private MockMvc mockMvc;
@BeforeEach void setUp() throws Exception { MockitoAnnotations.initMocks(this);//必须初始化,否则无法注入 OrderAppService mockMvc = MockMvcBuilders.standaloneSetup(ordersController).build(); Mockito.when(orderAppService.placeOrder(ArgumentMatchers.any(Order.class))).thenReturn(2L); }
@Test void test() throws Exception { mockMvc.perform(post("/orders/createOrder") // 发起post请求 .contentType(MediaType.APPLICATION_JSON_UTF8)).andExpect(status().isOk()) //希望请求处理成功(isOk()会判断HTTP 200响应码) .andExpect(MockMvcResultMatchers.jsonPath("$.code", is(0))) .andExpect(MockMvcResultMatchers.jsonPath("$.data", is(2))) .andExpect(MockMvcResultMatchers.jsonPath("$.message", is("success"))); }
}
复制代码


  1. @MockBean 创建模拟。这也可以通过使用 org.mockito.mock 方法实现。

  2. @InjectMocks 自动将模拟或间谍字段注入测试对象。

  3. MockitoAnnotations.initMocks(this)初始化了使用 Mockito 注释的字段。

  4. MockMvcBuilders.standaloneSetup(…).build() 通过注册一个或多个实例和以编程方式配置 spring MVC @Controller 基础结构来构建 MockMvc 实例。


webAppContextSetup

@RunWith(SpringRunner.class)@SpringBootTestclass OrdersControllerTest {
@Autowired private WebApplicationContext wac;//注入WebApplicationContext
@MockBean//可以将 mock 对象注入到 WebApplicationContext中 private OrderAppService orderAppService;
private MockMvc mockMvc;
@BeforeEach void setUp() throws Exception { mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); Mockito.when(orderAppService.placeOrder(ArgumentMatchers.any(Order.class))).thenReturn(2L); }
@Test void test() throws Exception { mockMvc.perform(post("/orders/createOrder") // 发起post请求 .contentType(MediaType.APPLICATION_JSON_UTF8)).andExpect(status().isOk()) //希望请求处理成功(isOk()会判断HTTP 200响应码) .andExpect(MockMvcResultMatchers.jsonPath("$.code", is(0))) .andExpect(MockMvcResultMatchers.jsonPath("$.data", is(2))) .andExpect(MockMvcResultMatchers.jsonPath("$.message", is("success"))); }
}
复制代码


  1. 与单独测试不同,应为使用了 WebApplicationContext ,所以在获取 Controller 的时候,就可以对 Service 进行 Mock


Mvc 测试的一般流程

  1. 准备测试环境

  2. 通过 MockMvc 执行请求

  3. 添加验证断言

  4. 添加结果处理器

  5. 得到 MvcResult 进行自定义断言/进行下一步的异步请求

  6. 卸载测试环境


参考资料

  1. 3.7. MockMvc


发布于: 2020 年 12 月 14 日阅读数: 35
用户头像

引花眠

关注

还未添加个人签名 2018.06.11 加入

还未添加个人简介

评论

发布
暂无评论
SpringBoot系列(6)- 测试