当前位置: 首页 > news >正文

Mock与Stub


一、核心概念与差异对比

特性MockStub
核心目的验证对象间的交互行为提供预定义的固定响应
验证重点方法调用次数、参数、顺序不关注调用过程,只关注结果
行为模拟可编程的智能模拟静态的简单响应
适用场景验证协作关系隔离依赖、提供固定数据
复杂性较高(需要设置预期行为)较低(简单硬编码响应)

架构决策点:选择Mock还是Stub取决于测试目标 - 验证交互行为用Mock,替换依赖项用Stub


二、架构设计中的分层应用

测试金字塔中的定位
UI Tests
Integration Tests
Unit Tests
Mock
Stub
  • 单元测试层:Mock主导(验证类间协作)
  • 集成测试层:Stub主导(模拟外部依赖)
  • 端到端测试:真实依赖(不使用模拟)
Spring测试架构
// 典型Spring测试分层
@SpringBootTest // 集成测试
class IntegrationTest {@MockBean DependencyService service; // MockBean替代真实依赖@Test void testIntegration() {// 使用Stub提供预设数据given(service.getData()).willReturn(new Data("stub value"));}
}@ExtendWith(MockitoExtension.class) // 单元测试
class UnitTest {@Mock Dependency dependency;@InjectMocks ServiceUnderTest service;@Test void testBehavior() {// 设置Mock行为并验证交互when(dependency.process(any())).thenReturn(true);service.execute();verify(dependency, times(1)).process(any());}
}

三、Spring生态中的实现详解

1. Stub实现方案

场景:为支付网关提供测试响应

// 定义支付网关接口
public interface PaymentGateway {PaymentResult charge(Order order);
}// 创建Stub实现
public class StubPaymentGateway implements PaymentGateway {private final PaymentResult fixedResult;public StubPaymentGateway(PaymentResult result) {this.fixedResult = result;}@Overridepublic PaymentResult charge(Order order) {// 静态响应,不包含业务逻辑return fixedResult;}
}// 测试中使用
@Test
void testOrderProcessingWithStub() {// 创建带成功响应的StubPaymentGateway stubGateway = new StubPaymentGateway(new PaymentResult("SUCCESS", "TX-123"));OrderService service = new OrderService(stubGateway);Order order = new Order(100.0);service.process(order);assertThat(order.getStatus()).isEqualTo(OrderStatus.PAID);
}
2. Mock实现方案(Mockito框架)

场景:验证库存服务调用

@ExtendWith(MockitoExtension.class)
class InventoryServiceTest {@Mock InventoryRepository mockRepo; // 创建Mock对象@InjectMocks InventoryService inventoryService; // 注入被测试对象@Testvoid shouldUpdateInventoryWhenOrderPaid() {// 准备测试数据Order order = new Order("order-1");order.addItem("prod-001", 2);// 设置Mock行为when(mockRepo.findByProductId("prod-001")).thenReturn(new Inventory("prod-001", 10));// 执行测试inventoryService.updateInventory(order);// 验证交互行为verify(mockRepo, times(1)).findByProductId("prod-001");verify(mockRepo, times(1)).save(argThat(inv -> inv.getQuantity() == 8)); // 验证保存参数// 验证未发生的方法调用verify(mockRepo, never()).delete(any());}
}

四、高级模式与应用场景

1. 部分Mock(Spy对象)

场景:测试复杂服务中的特定方法

@Spy // 部分Mock:真实对象+可Mock特定方法
private EmailService emailService;@Test
void testOrderNotification() {// 模拟发送邮件方法doNothing().when(emailService).sendConfirmation(any());orderService.processOrder(order);verify(emailService).sendConfirmation(order);
}
2. Spring Cloud Contract(契约测试)

架构方案:跨服务边界的Stub管理

生成Stub
测试时下载
Provider
Stub Repository
Consumer

提供方(定义契约):

// payment-contract.groovy
Contract.make {request {method POST()url '/payments'body([orderId: anyUuid(),amount: anyPositiveDouble()])}response {status 201body([status: "SUCCESS",transactionId: regex('[0-9a-f]{8}-[0-9a-f]{4}')])}
}

消费方(测试中使用Stub):

@SpringBootTest
@AutoConfigureStubRunner(ids = "com.example:payment-service:+:stubs")
class OrderServiceContractTest {@Testvoid shouldProcessPayment() {PaymentResult result = paymentClient.charge(new PaymentRequest(...));assertThat(result.getStatus()).isEqualTo("SUCCESS");}
}

五、架构师的最佳实践建议

  1. 分层使用策略

    • 单元测试:80% Mock + 20% Stub
    • 集成测试:20% Mock + 80% Stub
    • 契约测试:100% Stub(基于提供方契约)
  2. 性能优化

    // 重用Mock对象提升测试速度
    @MockitoSettings(strictness = Strictness.LENIENT)
    public class ReusableMocksTest {@Mock static DatabaseConnection sharedConnection;
    }
    
  3. 反模式警示

    • ❌ 过度验证:verify(mock, times(3)).trivialMethod()
    • ❌ Mock传递:when(mockA.call()).thenReturn(mockB)
    • ❌ 脆弱的Stub:硬编码不合理的测试数据
  4. 现代替代方案

    • 虚拟服务(Testcontainers):代替Stub提供更真实的模拟
    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15");
    
    • 代码生成Stub(OpenAPI Generator):基于API规范自动生成

六、架构决策树

graph TDA[需要测试什么?] A --> B{验证对象交互?}B -->|是| C[使用Mock]B -->|否| D{需要控制依赖行为?}D -->|是| E[使用Stub]D -->|否| F[使用真实对象]C --> G{需要部分真实行为?}G -->|是| H[使用Spy]G -->|否| I[使用纯Mock]E --> J{跨服务边界?}J -->|是| K[使用契约测试Stub]J -->|否| L[使用简单Stub实现]

作为系统架构师,我建议:在保证测试质量的前提下选择最简单的模拟方案。Mock适合验证内部协作,Stub适合隔离外部依赖,契约测试Stub则是微服务架构的必备工具。正确使用这些技术可以构建快速、可靠且维护成本低的测试体系。

http://www.dtcms.com/a/325134.html

相关文章:

  • 组合期权:水平价差
  • day29 消息队列
  • CST支持对哪些模型进行特征模仿真?分别有哪些用于特征模分析的求解器?
  • 信号处理函数中调用printf时,遇到中断为什么容易导致缓冲区损坏?
  • 介绍一下线程的生命周期及状态?
  • 化工设备健康管理解决方案:基于多物理场监测的智能化技术实现
  • 【系统分析师】软件需求工程——第11章学习笔记(上)
  • 堆(Java实现)
  • 大数据架构演变之路
  • [激光原理与应用-222]:机械 - 3D设计与2D设计的异同比较
  • 赋值运算符指南
  • GoBy 工具安装 | Windows 操作系统安装 GoBy
  • 某市智慧社区企业管理平台原型设计:数据驱动的社区治理新路径
  • 常用hook钩子函数
  • 设备活动审计技术方案解析
  • WSL创建虚拟机配置VNC
  • Linux系统编程——进程控制
  • 编程基础之多维数组——计算鞍点
  • 六、RuoYi-Cloud-Plus OSS文件上传配置
  • [Python 基础课程]常用函数
  • 数学与应用数学专业大学如何规划?就业前景怎么样?
  • vue3中 getCurrentInstance
  • 疯狂星期四文案网第35天运营日记
  • 补卡day16
  • special topic 8 (2) and topic 9 (1)
  • 亚麻云之全球加速器——CloudFront(CDN)服务入门
  • 系统测试讲解 - Java使用selenium实现滑块验证的处理详解
  • 关于linux操作系统下的文件操作方法:
  • 深度解析1688关键字搜索API接口:技术实现与应用探索
  • 【Nginx知识】nginx日志配置详解