如何将Mock对象伪装成PyQt可接受的对象传入Qt方法参数?
PyQt测试中Mock对象作为父类参数的类型错误问题
以下是最小可复现示例(MRE),需安装pytest,安装pytest-qt会更方便。
import sys, pytest from PyQt5 import QtWidgets from unittest import mock class MyLineEdit(QtWidgets.QLineEdit): def __init__(self, parent): super().__init__(parent) self.setPlaceholderText('bubbles') class Window(QtWidgets.QWidget): def __init__(self): super().__init__() self.setWindowTitle("Pytest MRE") self.setMinimumSize(400, 200) layout = QtWidgets.QVBoxLayout() qle = MyLineEdit(self) layout.addWidget(qle) self.setLayout(layout) if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) window = Window() window.show() sys.exit(app.exec_()) def test_MyLineEdit_sets_a_title(): mock_window = mock.Mock(spec=QtWidgets.QWidget) print(f'mock_window.__class__ {mock_window.__class__}') # 输出 "QWidget" print(f'type(mock_window) {type(mock_window)}') # 输出 "mock.Mock" with mock.patch('PyQt5.QtWidgets.QLineEdit.setPlaceholderText') as mock_set_placeholder: # with mock.patch('PyQt5.QtWidgets.QLineEdit.__init__') as mock_super_init: my_line_edit = MyLineEdit(mock_window) mock_set_placeholder.assert_called_once() assert False
运行测试时会触发如下类型错误:
E TypeError: arguments did not match any overloaded call: E QLineEdit(parent: Optional[QWidget] = None): argument 1 has unexpected type 'Mock' E QLineEdit(contents: Optional[str], parent: Optional[QWidget] = None): argument 1 has unexpected type 'Mock' test_grey_out_qle_exp.py:7: TypeError
这是PyQt应用测试中的常见问题:试图将Mock对象传入PyQt类方法(比如构造函数)时,会触发类型校验错误。如果改用真实的QtWidget(或其他PyQt类对象)作为参数,又会引发各类问题,甚至在Windows系统出现间歇性访问违规错误。
已尝试过MagicMock、spec、autospec等方式伪装Mock对象,但PyQt总能识别出真实类型——推测它是通过内置type()函数做类型校验的。也曾尝试过修补type()函数,但未找到可行方案。目前临时方案是修补引发问题的PyQt父类方法;还试过继承QWidget和Mock的混合Mock类,但在Windows 10上运行pytest时直接崩溃。
内容的提问来源于stack exchange,提问作者mike rodent
相关产品推荐
相关产品推荐

