如何使用pytest-qt测试QFileDialog的directoryEntered信号触发槽函数
问题分析
- 时序逻辑错误:
waitSignal必须在信号触发前启动监听,你之前的写法要么先发射信号再调用waitSignal,信号已经触发完了才开始监听自然捕获不到;要么先调用waitSignal,阻塞到超时才会执行后面的信号发射逻辑,自然也捕获不到。 - Mock生命周期错误:你把信号触发逻辑放在
with mock.patch块内部,但槽函数是Qt事件循环异步执行的,等事件循环处理信号调用槽函数的时候,with块已经退出,mock 已经被还原为原生方法,当然统计不到调用次数。 - 冗余操作:既然你已经确认connect绑定正常,直接emit信号测试逻辑即可,不需要额外找原生按钮点击,增加不必要的复杂度。
正确测试代码
import pathlib from unittest import mock from PyQt5 import QtWidgets, QtCore # 这里替换为你自己的SaveProjectDialog导入路径 from save_project_dialog_class import SaveProjectDialog def test_directoryEntered_triggers_on_dir_entered(qtbot, tmpdir): project = mock.Mock() project.main_window = QtWidgets.QWidget() project.home_dir_path = pathlib.Path(str(tmpdir)) fd = SaveProjectDialog(project) # mock 作用域覆盖整个信号处理周期 with mock.patch.object(fd, 'on_dir_entered') as mock_entered: # waitSignal 作为上下文管理器,进入即开始监听信号,块内执行触发信号的逻辑 with qtbot.waitSignal(fd.directoryEntered, timeout=1000): fd.directoryEntered.emit('dummy') # 退出waitSignal块时信号已处理完成,mock仍在生效期,可正常断言 mock_entered.assert_called_once_with('dummy')
原理解释
qtbot.waitSignal作为上下文管理器使用时,进入代码块就会启动对目标信号的监听,代码块内执行触发信号的逻辑,整个块会阻塞直到收到目标信号或者超时,退出块时事件循环已经处理完该信号关联的所有槽函数调用。再配合外层的mock作用域覆盖整个处理周期,就能正确统计槽函数的调用情况。
内容的提问来源于stack exchange,提问作者mike rodent
相关产品推荐
相关产品推荐

