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

Hippomocks值类型成员Mock无法触发异常问题求助

为什么Foo2的Mock会失败?如何在不修改类的前提下解决?

这是个典型的多态Mock在值类型和指针类型上的差异问题,我来帮你拆解清楚:

一、Foo1与Foo2的核心差异原因

Hippomocks的Mock机制完全依赖C++多态来工作:它创建的IBar*实际上是一个动态生成的IBar子类实例,这个子类重写了所有虚函数,加入了Hippomocks的调用拦截、预期检查逻辑。

1. Foo1(指针成员)能正常工作的原因

你把Mock对象的指针直接赋值给g->bar,当调用g->a()时,是通过指针调用虚函数,触发了多态机制——实际执行的是Mock子类重写的c()方法,自然能被Hippomocks拦截,抛出预期的异常。

2. Foo2(值类型成员)Mock失败的根源

你用memcpy(&g->bar, b, sizeof(*b))的操作完全搞错了方向:

  • g->bar是一个栈上的原始IBar值对象,而b指向的是堆上的Mock子类实例。memcpy只是把Mock对象的前sizeof(IBar)字节(也就是基类部分)复制到g->bar里,但这会破坏多态的核心——虚函数表(vtable):
    • 复制后g->bar的类型依然是IBar,它的虚表指针并没有指向Mock子类的虚表,调用this->bar.c()时,还是执行原始IBar的c()方法,根本没走到Mock的拦截逻辑。
    • 这种直接复制多态对象内存的操作本身就是未定义行为,可能导致虚表混乱、内存错误,完全不符合C++对象模型的规则。

这就是为什么你会看到HippoMocks::CallMissingException——Hippomocks记录了预期调用,但实际根本没人触发它。

二、不修改Foo2类的解决方案

Hippomocks专门提供了Inject方法,可以把Mock的虚表注入到一个已存在的对象实例中,完美解决值类型成员的Mock问题。修改你的test_a()函数如下:

void TestTest::test_a(){
    /////// Test hippomock /////////////////////
    MockRepository mocks;
    IBar *b = mocks.Mock<IBar>();
    Foo2 *g = new Foo2();
    
    // 关键:用Inject将Mock的虚表注入到g->bar对象中
    mocks.Inject(&g->bar, b);
    
    mocks.ExpectCall(&g->bar, IBar::c).Throw(std::exception());
    CPPUNIT_ASSERT_THROW (g->a(), std::exception);
    
    // 记得清理内存,避免泄漏
    delete g;
    /////// Test hippomock end /////////////////////
}

为什么这个方法有效?

Inject方法会安全地修改目标对象(g->bar)的虚函数表指针,让它指向Hippomocks生成的Mock子类的虚表。这样即使g->bar是值类型的IBar对象,调用它的虚函数时,也会执行Mock的拦截逻辑,触发你预期的异常。

注意事项

  • 确保目标对象的类是多态类型(也就是有至少一个虚函数,这里IBar有虚析构和虚的c()方法,满足要求)。
  • 测试结束后,MockRepository会自动清理相关资源,不需要手动恢复目标对象的虚表(因为测试结束后g->bar也会被销毁)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:19:57