如何让GMock模拟的Qt类触发的Signal被消费者正确接收?
这个测试场景完全可以实现,你遇到的问题是Qt信号槽机制的几个常见配置遗漏导致的,和GMock没有冲突,以下是具体原因和修复方案:
问题根因
- 模拟类缺失Q_OBJECT宏
你定义的UploaderMock继承自QObject的子类IUploader,但没有添加Q_OBJECT宏,Qt元对象系统无法为该类生成完整的元信息,信号槽通信会静默失败。 - 测试工程未正确处理moc编译
测试目录下的UploaderMock.h如果没有被加入工程的AUTOMOC处理范围,即使加了Q_OBJECT宏,也不会生成对应的元对象代码,导致信号槽连接失效。 - 队列连接模式下缺少事件循环
如果你的代码中显式指定了Qt::QueuedConnection作为连接类型,或是发送/接收对象被移动到了不同线程,默认的AutoConnection会自动切换为队列连接,信号会进入事件队列等待处理。而你的测试代码没有运行事件循环,所以槽函数不会被触发。 - 缺少Qt应用实例
Qt的元对象系统和事件循环依赖QCoreApplication实例,如果你在测试入口的main函数中没有创建该实例,所有信号槽相关逻辑都会失效。
修复步骤
- 给
UploaderMock添加Q_OBJECT宏,调用信号时加emit关键字:
class UploaderMock : public IUploader { Q_OBJECT public: MOCK_METHOD(void, upload, (int i), (override)); };
对应ON_CALL的动作修改为:
ON_CALL(uploader, upload(11)).WillByDefault([&uploader](int i) { emit uploader.finished(i * 2); });
- 调整测试工程配置
开启测试目标的AUTOMOC选项,将UploaderMock.h加入工程的源文件/头文件列表,确保moc工具可以处理该文件。 - 测试入口初始化QCoreApplication
在测试的main函数中添加QCoreApplication实例:
int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }
- 手动处理事件队列(针对队列连接场景)
如果你的业务逻辑确实使用队列连接,在触发操作后添加事件处理代码:
// act consumer.doUpload(11); // 处理所有待处理事件 QCoreApplication::processEvents(); // assert EXPECT_EQ(consumer.uploadResult(), 22);
如果需要等待异步操作完成,可以加超时等待逻辑:
QElapsedTimer timer; timer.start(); while (consumer.uploadResult() == -1 && timer.elapsed() < 1000) { QCoreApplication::processEvents(); }
内容的提问来源于stack exchange,提问作者Damir Porobic
相关产品推荐
相关产品推荐

