求个网站好人有好报2022,河南网络营销哪家便宜,十大电商平台有哪些,优酷wordpress建站教程如何写好单元测试#xff1a;Mock 脱离数据库#xff0c;告别 SpringBootTest 的重型启动 作者#xff1a;Killian#xff08;重庆#xff09; — 欢迎各位架构猎头、技术布道者联系我#xff0c;项目实战丰富#xff0c;代码稳健#xff0c;Mock测试爱好者。 技术栈Mock 脱离数据库告别 SpringBootTest 的重型启动 作者Killian重庆 — 欢迎各位架构猎头、技术布道者联系我项目实战丰富代码稳健Mock测试爱好者。 技术栈Java 17、JUnit 5、Mockito 5、Spring Boot 3.x可选 一、前言
你是否遇到过以下问题
每次跑测试都要加载整个 Spring 容器慢如蜗牛明明只测一个方法却启动了 Redis、MySQL、MQ 等服务想 Mock 一个 Bean 却被 Autowired 绑死
这时候我们该说不需要 SpringBootTest
本篇文章将系统讲解
如何编写真正的“单元”测试Unit Test如何使用 Mockito 精准 Mock 依赖避免启动数据库等外部依赖如何写出高覆盖率、快反馈、可维护的业务逻辑测试 二、为什么要避免 SpringBootTest
问题描述启动慢SpringBootTest 会加载整个上下文Controller、Service、Repository、Config依赖重需要配置数据库、缓存、RabbitMQ 等外部环境不稳定环境不一致容易导致测试 flaky有时通过有时失败非单元测试实际上是“集成测试”容易误用 三、正确的方式使用 Mockito JUnit 写真正的单元测试
示例背景
我们有一个服务类
Service
public class OrderService {private final OrderRepository orderRepository;private final PaymentClient paymentClient;public OrderService(OrderRepository orderRepository, PaymentClient paymentClient) {this.orderRepository orderRepository;this.paymentClient paymentClient;}public String pay(String orderId) {Order order orderRepository.findById(orderId).orElseThrow(() - new RuntimeException(订单不存在));if (order.isPaid()) {return 重复支付;}boolean result paymentClient.callPayGateway(order);if (result) {order.markPaid();orderRepository.save(order);return 支付成功;} else {return 支付失败;}}
}单元测试写法脱离容器 Mock 依赖
ExtendWith(MockitoExtension.class)
class OrderServiceTest {Mock OrderRepository orderRepository;Mock PaymentClient paymentClient;InjectMocks OrderService orderService;TestDisplayName(支付成功时订单状态应更新并保存)void testPaySuccess() {Order mockOrder new Order(123, false);when(orderRepository.findById(123)).thenReturn(Optional.of(mockOrder));when(paymentClient.callPayGateway(mockOrder)).thenReturn(true);String result orderService.pay(123);assertEquals(支付成功, result);assertTrue(mockOrder.isPaid());verify(orderRepository).save(mockOrder);}TestDisplayName(找不到订单时应抛出异常)void testOrderNotFound() {when(orderRepository.findById(999)).thenReturn(Optional.empty());assertThrows(RuntimeException.class, () - orderService.pay(999));}TestDisplayName(已支付订单不应重复支付也不应保存)void testAlreadyPaid() {Order paidOrder new Order(456, true);when(orderRepository.findById(456)).thenReturn(Optional.of(paidOrder));String result orderService.pay(456);assertEquals(重复支付, result);verify(orderRepository, never()).save(any());}
}四、关键技巧Mock 什么怎么 Mock
1. 只 Mock “外部依赖”
数据库 Repository第三方客户端如 FeignClient、HttpClientRedis 操作、MQ 发送器、ES 操作器
2. 不 Mock 的部分
自己写的业务逻辑类即你要测的类
3. 使用 Mockito 提供的能力
when(...).thenReturn(...)设置返回值verify(...)验证方法是否调用argThat(...)匹配参数条件doThrow(...)模拟异常 五、单元测试 vs 集成测试职责边界与框架选择
对比表格
维度单元测试Unit Test集成测试Integration Test启动方式不启动 Spring 容器启动 Spring 容器或部分测试目标业务逻辑、算法正确性Bean 交互、配置、环境集成Mock 使用必须 Mock 外部依赖通常不 Mock使用真实组件性能快毫秒级慢秒级数据源无数据库或 H2 Mock真正连接数据库如 Docker 启动 MySQL断言粒度精确控制方法行为更偏向流程通路与集成稳定性 DataJpaTest
用于测试 JPA Repository 层不加载 Service、Controller
DataJpaTest
class UserRepositoryTest {Autowired UserRepository repo;TestDisplayName(根据用户名查询用户应返回结果)void testFindByUsername() {User u new User(tom, 123);repo.save(u);assertTrue(repo.findByUsername(tom).isPresent());}
}自动配置内嵌数据库如 H2速度适中适合数据层测试。 Mapper MyBatis 的 Mapper 层测试两种方式
✅ 方式一真实数据库 MybatisTest
MybatisTest
AutoConfigureTestDatabase(replace AutoConfigureTestDatabase.Replace.NONE) // 保持使用真实数据库配置
class OrderMapperTest {Autowired OrderMapper orderMapper;TestDisplayName(根据订单ID查询应返回订单信息)void testSelectById() {Order order orderMapper.selectById(order123);assertNotNull(order);}
}说明
MybatisTest 会只加载 MyBatis 相关的配置不会加载 Service、Controller默认使用 H2可通过 AutoConfigureTestDatabase 强制保留 MySQL 等真实库可以测试 XML 映射、注解 SQL、分页插件等
✅ 方式二Mock Mapper更适合单元测试
ExtendWith(MockitoExtension.class)
class OrderServiceTest {Mock OrderMapper orderMapper;InjectMocks OrderService orderService;TestDisplayName(Mock Mapper 查询订单应返回正确订单)void testOrderFetch() {Order mockOrder new Order(order789, false);when(orderMapper.selectById(order789)).thenReturn(mockOrder);Order result orderService.getOrder(order789);assertEquals(order789, result.getId());}
}说明
Mapper 在 Service 中作为依赖Mock 掉即可测试业务逻辑不需要数据库、不用 SpringBootTest速度快、适合 CI WebMvcTest
用于测试 Controller 层不加载业务逻辑
WebMvcTest(UserController.class)
class UserControllerTest {Autowired MockMvc mockMvc;MockBean UserService userService;TestDisplayName(调用 /hello 接口应返回 hello tom)void testHelloApi() throws Exception {when(userService.getName()).thenReturn(tom);mockMvc.perform(get(/hello)).andExpect(status().isOk()).andExpect(content().string(hello tom));}
}优点是启动快只加载 Web 层相关 Bean可精准控制 Controller 输入输出。 要点说明不使用 SpringBootTest减少启动时间提高测试速度用 ExtendWith(MockitoExtension.class)使用 Mockito 管理依赖注入用 InjectMocks注入被测类业务类用 Mock模拟依赖Repository、外部接口每个测试只验证一件事保证测试原子性和可维护性 六、扩展阅读
Mockito 官方文档https://site.mockito.orgJUnit 5 用户指南https://junit.org/junit5/docs/current/user-guide/推荐阅读Martin Fowler《Unit Test vs Integration Test》 七、结语
如果你写单元测试还依赖 SpringBootTest那就像每次微波炉加热都要重启电厂。Mock 依赖、聚焦业务、轻量高效才是测试真正的姿势。
下一次写测试时请问自己“我是在测试业务逻辑还是在启动一个服务器” 本文由 killian 原创转载请注明出处。 ☕ 请作者喝杯咖啡持续更新更深入的干货 彩蛋时间如果你看到了这里说明你是那种喜欢动手实战的人。那我悄悄分享一个开发圈流传的工具试用入口貌似跟高效调试很有关系地址也挺特别的 入口
据说注册还能解锁一些隐藏功能懂的都懂别外传 文章转载自: http://www.morning.blznh.cn.gov.cn.blznh.cn http://www.morning.rlksq.cn.gov.cn.rlksq.cn http://www.morning.rjljb.cn.gov.cn.rjljb.cn http://www.morning.xrmwc.cn.gov.cn.xrmwc.cn http://www.morning.wlnr.cn.gov.cn.wlnr.cn http://www.morning.gmnmh.cn.gov.cn.gmnmh.cn http://www.morning.sqfrg.cn.gov.cn.sqfrg.cn http://www.morning.dtmjn.cn.gov.cn.dtmjn.cn http://www.morning.hmgqy.cn.gov.cn.hmgqy.cn http://www.morning.jyjqh.cn.gov.cn.jyjqh.cn http://www.morning.rcmcw.cn.gov.cn.rcmcw.cn http://www.morning.bntfy.cn.gov.cn.bntfy.cn http://www.morning.vattx.cn.gov.cn.vattx.cn http://www.morning.nqpxs.cn.gov.cn.nqpxs.cn http://www.morning.rszyf.cn.gov.cn.rszyf.cn http://www.morning.zymgs.cn.gov.cn.zymgs.cn http://www.morning.jcrlx.cn.gov.cn.jcrlx.cn http://www.morning.tyklz.cn.gov.cn.tyklz.cn http://www.morning.hkpn.cn.gov.cn.hkpn.cn http://www.morning.hslgq.cn.gov.cn.hslgq.cn http://www.morning.hphfy.cn.gov.cn.hphfy.cn http://www.morning.msgnx.cn.gov.cn.msgnx.cn http://www.morning.qznkn.cn.gov.cn.qznkn.cn http://www.morning.cxryx.cn.gov.cn.cxryx.cn http://www.morning.bxqry.cn.gov.cn.bxqry.cn http://www.morning.ydnxm.cn.gov.cn.ydnxm.cn http://www.morning.ggcjf.cn.gov.cn.ggcjf.cn http://www.morning.znlhc.cn.gov.cn.znlhc.cn http://www.morning.pwfwk.cn.gov.cn.pwfwk.cn http://www.morning.prplf.cn.gov.cn.prplf.cn http://www.morning.ysbhj.cn.gov.cn.ysbhj.cn http://www.morning.fhjnh.cn.gov.cn.fhjnh.cn http://www.morning.neletea.com.gov.cn.neletea.com http://www.morning.fpyll.cn.gov.cn.fpyll.cn http://www.morning.gbyng.cn.gov.cn.gbyng.cn http://www.morning.kflbf.cn.gov.cn.kflbf.cn http://www.morning.yhjrc.cn.gov.cn.yhjrc.cn http://www.morning.mhcys.cn.gov.cn.mhcys.cn http://www.morning.wlqbr.cn.gov.cn.wlqbr.cn http://www.morning.tjwfk.cn.gov.cn.tjwfk.cn http://www.morning.srxhd.cn.gov.cn.srxhd.cn http://www.morning.qcnk.cn.gov.cn.qcnk.cn http://www.morning.rgnq.cn.gov.cn.rgnq.cn http://www.morning.qkskm.cn.gov.cn.qkskm.cn http://www.morning.psqs.cn.gov.cn.psqs.cn http://www.morning.qsy39.cn.gov.cn.qsy39.cn http://www.morning.jzlkq.cn.gov.cn.jzlkq.cn http://www.morning.hnhkz.cn.gov.cn.hnhkz.cn http://www.morning.wqpr.cn.gov.cn.wqpr.cn http://www.morning.nynlf.cn.gov.cn.nynlf.cn http://www.morning.xhwty.cn.gov.cn.xhwty.cn http://www.morning.ymwcs.cn.gov.cn.ymwcs.cn http://www.morning.wdhlc.cn.gov.cn.wdhlc.cn http://www.morning.rdnjc.cn.gov.cn.rdnjc.cn http://www.morning.rwjh.cn.gov.cn.rwjh.cn http://www.morning.bpmfz.cn.gov.cn.bpmfz.cn http://www.morning.mkfhx.cn.gov.cn.mkfhx.cn http://www.morning.khtyz.cn.gov.cn.khtyz.cn http://www.morning.nrwr.cn.gov.cn.nrwr.cn http://www.morning.dqrhz.cn.gov.cn.dqrhz.cn http://www.morning.nxbkw.cn.gov.cn.nxbkw.cn http://www.morning.qgzmz.cn.gov.cn.qgzmz.cn http://www.morning.pqxjq.cn.gov.cn.pqxjq.cn http://www.morning.prfrb.cn.gov.cn.prfrb.cn http://www.morning.ztqyj.cn.gov.cn.ztqyj.cn http://www.morning.wfjyn.cn.gov.cn.wfjyn.cn http://www.morning.dbddm.cn.gov.cn.dbddm.cn http://www.morning.xdpjs.cn.gov.cn.xdpjs.cn http://www.morning.crfyr.cn.gov.cn.crfyr.cn http://www.morning.hrpjx.cn.gov.cn.hrpjx.cn http://www.morning.ywxln.cn.gov.cn.ywxln.cn http://www.morning.jfxdy.cn.gov.cn.jfxdy.cn http://www.morning.rdwm.cn.gov.cn.rdwm.cn http://www.morning.rqlf.cn.gov.cn.rqlf.cn http://www.morning.pswqx.cn.gov.cn.pswqx.cn http://www.morning.linzhigongmao.cn.gov.cn.linzhigongmao.cn http://www.morning.knqck.cn.gov.cn.knqck.cn http://www.morning.tgyzk.cn.gov.cn.tgyzk.cn http://www.morning.tkxyx.cn.gov.cn.tkxyx.cn http://www.morning.yrnrr.cn.gov.cn.yrnrr.cn