应通过集成测试覆盖对象协作流程,聚焦接口契约与状态流转,隔离外部依赖并用mock控制返回值和调用次数,验证端到端输入→行为→可观测输出的完整业务结果。

用集成测试覆盖对象协作流程,而不是硬塞进单元测试
多个对象协作完成的业务流程,本质是接口契约与状态流转的组合,不是单个函数能 cover 的。强行在 TEST 里 new 一堆对象、手动调用、断言中间状态,会带来三类问题:一是测试脆弱(改一个构造参数或内部字段顺序就全挂);二是逻辑泄露(测试代码重复实现业务判断逻辑);三是掩盖真实依赖(比如漏掉某对象实际依赖了全局时钟或配置单例)。真正该测的是“输入→系统行为→可观测输出”这条端到端链路,且必须隔离外部扰动。
先抽离可替换的依赖边界,再组装协作场景
协作流程崩得快,往往因为对象之间耦合了不可控资源。比如一个订单服务依赖实时库存查询、支付网关、短信通知——这些都不能在测试里真调。必须提前识别并抽象出接口:
-
IInventoryService、IPaymentGateway、INotificationSender这类命名要体现职责,而非技术实现(别叫HttpInventoryClient) - 所有依赖必须通过构造函数注入,禁止在类内部 new 或调用静态单例
- 为每个接口写轻量 mock 实现(用 Google Test 的
MOCK_METHOD或手写 stub),重点控制返回值和调用次数,不模拟复杂状态机
示例中,测试下单流程时让 MockInventoryService 对特定 SKU 返回 in_stock = false,就能验证库存不足时是否正确回滚并抛出 InsufficientStockError,而无需启动 Redis 或数据库。
用真实数据驱动流程断言,避免只验“有没有调用”
很多团队的“集成测试”只停留在“mock 调用了 3 次”,这毫无意义。协作流程的价值在于状态累积与副作用,必须验证最终结果是否符合业务预期:
立即学习“C++免费学习笔记(深入)”;
- 输入一个订单请求,检查数据库里是否生成了
order记录 +order_item明细 +payment_attempt日志,且三者order_id一致 - 触发退款操作后,检查账户余额是否增加、订单状态是否变为
REFUNDED、是否向风控系统发出了回调事件 - 用
ASSERT_EQ对比完整对象状态,而不是只断言某个字段;对时间戳等易变字段,用范围断言(如abs(actual - expected) )
注意:这类测试需清理现场(如事务回滚、临时库 drop),否则一次失败会导致后续全部失败。Google Test 的 SetUpTestSuite/TearDownTestSuite 是合适位置,但别在每个 TEST 里做 DB truncate——太慢且易冲突。
并发协作流程必须显式控制线程时序
当流程涉及多线程协作(如异步通知+本地状态更新),直接跑测试大概率偶发失败。不能靠 std::this_thread::sleep_for 硬等,而要用同步原语把不确定性锁死:
- 用
std::condition_variable+std::atomic标记关键节点(如 “库存扣减完成”、“支付回调到达”) - 在被测对象中注入
std::shared_ptr<:mutex></:mutex>和std::shared_ptr<:condition_variable></:condition_variable>,测试代码持有同一份实例来 wait/notify - 避免测试代码和被测代码共享裸指针或引用,防止析构顺序引发 UAF
最容易被忽略的是内存序:std::atomic 默认是 memory_order_seq_cst,够用;但如果 mock 里用了 relaxed load/store,可能造成测试里看到“已通知”但实际状态未更新——这种 bug 在生产环境才会暴露。


















