抽象基类测试需通过派生stub类或Google Mock实现:stub类覆写全部纯虚函数并调用基类构造函数;Mock类继承ABC并用MOCK_METHOD精确匹配函数签名,配合EXPECT_CALL验证契约。

抽象基类不能直接实例化,怎么写测试?
抽象基类(ABC)本身不能 new 或声明对象,所以测试不能像普通类那样直接构造——必须通过派生类或 mock 实现。这是最常卡住的地方:一写 MyAbstractClass obj; 就报错 cannot declare variable 'obj' because the type is abstract。
核心思路只有两个:要么写一个最小派生类(stub),要么用 Google Mock 等框架伪造实现。前者轻量、无依赖,适合单元测试;后者灵活,适合需要控制行为的场景。
- Stub 派生类只需覆写所有纯虚函数,哪怕只返回默认值(
return 0;、return "";) - 如果抽象基类有带参数的构造函数,stub 类必须显式调用它:
Stub() : MyAbstractClass(42) {} - 不要在 stub 里加额外逻辑——它只是让编译通过的“占位符”,否则会污染测试边界
Google Mock 怎么 mock 抽象基类?
Mock 类必须继承自抽象基类,并用 MOCK_METHOD 覆盖每个纯虚函数。注意:函数签名(包括 const、noexcept、引用限定符)必须完全一致,否则链接时找不到实现,或运行时报 pure virtual function called。
示例:假设 class Shape { public: virtual double area() const = 0; };
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
class MockShape : public Shape {
public:
MOCK_CONST_METHOD0(area, double());
};
- 使用
MOCK_CONST_METHOD0对应const成员函数,参数个数为 0;有参数就用MOCK_METHOD1、MOCK_METHOD2等 - mock 对象需配合
EXPECT_CALL设置预期行为,否则调用未设定期望的虚函数会触发默认 panic(可关掉:GMOCK_DEFAULT_ACTION_FOR_UNEXPECTED_CALL) - 若基类析构函数不是
virtual,mock 类析构可能不安全——务必确认抽象基类有virtual ~MyAbstractClass() = default;
测试纯虚函数接口契约,而不是实现细节
抽象基类的价值在于定义接口契约(比如“所有派生类必须提供 serialize()”),测试重点应是:派生类是否满足该契约,而非抽象类内部逻辑(它本来就没有)。
- 对每个纯虚函数,写一个测试用例验证其基本行为:输入 X → 期望输出 Y 或抛出特定异常
- 用 stub 类测试多态调用路径:例如把 stub 对象传给接受
std::unique_ptr<MyAbstractClass>的函数,确认能正确调用到覆写版本 - 避免测试抽象类里的非虚成员函数(如果有)——它们属于具体实现,应由派生类测试覆盖;若真要测,说明设计可能已偏离抽象意图
常见编译错误和绕过方式
除了 “cannot declare variable”,还有几个高频报错:
-
undefined reference to 'vtable for XXX':通常因为某个纯虚函数没在派生类中实现,或忘记定义 mock 方法体(Google Mock 需要链接gmock_main) -
invalid new-expression of abstract type:试图new MyAbstractClass,必须改用new StubDerivedClass或std::make_unique<StubDerivedClass>() - 模板抽象类(如
template<typename T> class Container { virtual void push(const T&) = 0; };)测试时需显式指定模板参数:class StubContainerInt : public Container<int> { ... };
真正麻烦的是带私有纯虚函数或受保护析构的抽象类——这时只能靠友元测试类或调整访问权限,说明接口设计已增加测试成本。

















