You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Gtest Mock模拟resize与Getsize的指定时序竞态

结论

完全可以通过gtest配套的gMock能力实现这个精准时序的竞态场景模拟,而且不需要靠不稳定的随机休眠来碰调度时机,能做到100%复现你要的缓存不一致问题。

实现思路

你不需要在代码里硬编码延迟,核心做法是通过mock插桩,卡在resizeint执行完成、writenewsizetocache还未执行的精确代码点位,主动触发Getsize调用,完全控制执行时序。

第一步:做最小程度的依赖解耦

因为gMock默认对虚接口做动态mock,你需要先把resizeint、writenewsizetocache、readsizefromlocalcache这几个底层操作抽成可注入的接口,不需要改动原有业务逻辑,只是把硬编码的内部依赖改成外部传入即可:

// 抽离底层操作的抽象接口
class SharedObjectBase {
public:
  virtual ~SharedObjectBase() = default;
  virtual void resizeint(int newsize) = 0;
  virtual void writenewsizetocache() = 0;
  virtual int readsizefromlocalcache() = 0;
};

// 原有业务逻辑几乎不变,只是依赖抽象接口
class SizeHandler {
private:
  SharedObjectBase* obj_;
public:
  explicit SizeHandler(SharedObjectBase* obj) : obj_(obj) {}
  void Resize(int newsize) {
    obj_->resizeint(newsize);
    // 目标插桩点就在这两行中间
    obj_->writenewsizetocache();
  }
  int Getsize() {
    return obj_->readsizefromlocalcache();
  }
};

第二步:编写Mock类

用gMock的宏生成对应接口的mock实现:

class MockSharedObject : public SharedObjectBase {
public:
  MOCK_METHOD(void, resizeint, (int newsize), (override));
  MOCK_METHOD(void, writenewsizetocache, (), (override));
  MOCK_METHOD(int, readsizefromlocalcache, (), (override));
};

第三步:编写测试用例,通过mock动作控制时序

不要用sleep之类的延迟等待,直接用gMock的Invoke动作,在resizeint被调用的逻辑末尾,主动执行Getsize,这个时机完全卡在你要的两个操作中间,没有任何调度偏差:

TEST(CacheConsistencyTest, GetOldSizeWhenResizeNotFinishCacheUpdate) {
  MockSharedObject mock_obj;
  SizeHandler handler(&mock_obj);
  const int old_size = 100;
  const int new_size = 300;

  // 设定预期:读缓存时因为还没更新,返回旧尺寸
  EXPECT_CALL(mock_obj, readsizefromlocalcache())
    .WillOnce(testing::Return(old_size));
  // 设定预期:缓存写入操作会在resizeint之后执行
  EXPECT_CALL(mock_obj, writenewsizetocache())
    .Times(1);

  // 核心插桩逻辑:resizeint执行完立刻调用Getsize
  EXPECT_CALL(mock_obj, resizeint(new_size))
    .WillOnce(testing::Invoke([&](int) {
      // 这里就是目标精确点位:实际尺寸已经修改,缓存还未写入
      int ret = handler.Getsize();
      // 验证此时读到的确实是旧缓存值,复现不一致问题
      EXPECT_EQ(ret, old_size);
    }));

  // 执行Resize操作,时序完全按照设定执行
  handler.Resize(new_size);
}
方案说明
  • 没有任何不稳定的延迟等待,完全靠代码执行流控制时机,每次运行都能稳定复现场景
  • 不需要修改生产代码的业务逻辑,只做了依赖解耦,本身也符合代码设计的最佳实践
  • 如果你的底层函数是全局函数/静态函数,没法抽虚接口,也可以用gMock的编译期/链接期打桩能力实现同样的插桩效果,只是可维护性比接口注入稍差。

不要靠随机休眠模拟竞态:操作系统的线程调度是不可控的,哪怕你加固定时长的sleep,也可能出现调度偏差导致测试偶发失败,用mock主动在指定执行点插入逻辑才是可靠的方案。

内容的提问来源于stack exchange,提问作者vidhya gopalan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 01:01:14