PyQt与unittest - 测试信号和槽

4 投票
3 回答
3569 浏览
提问于 2025-04-15 17:54

我正在为一个用pyqt写的应用程序编写单元测试,这个应用程序非常依赖信号和槽。为了正确测试它,我需要检查是否发送了正确的信号。

那么,最好的方法是什么呢?我看到Qt库里有一个叫QSignalSpy的东西,但在PyQt中找不到相关的资料。我能想到的唯一办法就是模拟发送信号,比如:

import testedmodule

def myemit(signal):
    ....

testedmodule.QObject.emit = myemit

不过我希望能有更好的方法。

编辑:
我的模块是作为一个线程运行的,在这种情况下,启动线程后重写实例的发送信号功能就不再有效了,所以我更新了上面的代码以反映这一点。

3 个回答

1

注意,QSignalSpy在PyQt5中可以作为QtTest.QSignalSpy使用,详细信息可以查看这里

1

这是我自己建议的一个更详细的版本,虽然不一定是单元测试的最佳解决方案,但我觉得对其他遇到这个问题的人会有帮助:

由Carlos Scheidegger在pyqt邮件列表上发布(http://thread.gmane.org/gmane.comp.python.pyqt-pykde/9242/focus=9245

_oldConnect = QtCore.QObject.connect
_oldDisconnect = QtCore.QObject.disconnect
_oldEmit = QtCore.QObject.emit

def _wrapConnect(callableObject):
    """Returns a wrapped call to the old version of QtCore.QObject.connect"""
    @staticmethod
    def call(*args):
        callableObject(*args)
        _oldConnect(*args)
    return call

def _wrapDisconnect(callableObject):
    """Returns a wrapped call to the old version of QtCore.QObject.disconnect"""
    @staticmethod
    def call(*args):
        callableObject(*args)
        _oldDisconnect(*args)
    return call

def enableSignalDebugging(**kwargs):
    """Call this to enable Qt Signal debugging. This will trap all
    connect, and disconnect calls."""

    f = lambda *args: None
    connectCall = kwargs.get('connectCall', f)
    disconnectCall = kwargs.get('disconnectCall', f)
    emitCall = kwargs.get('emitCall', f)

    def printIt(msg):
        def call(*args):
            print msg, args
        return call
    QtCore.QObject.connect = _wrapConnect(connectCall)
    QtCore.QObject.disconnect = _wrapDisconnect(disconnectCall)

    def new_emit(self, *args):
        emitCall(self, *args)
        _oldEmit(self, *args)

    QtCore.QObject.emit = new_emit

只需调用enableSignalDebugging(emitCall=foo),然后监视你的信号,直到你感到恶心为止 :)

1

你可以试着把一个槽(也就是处理信号的函数)连接到你的信号上,然后准备好你的测试,接着调用 qApp.processEvents() 来让信号传播。不过,我觉得这样做并不是百分之百可靠。

真可惜,QSignalSpy 这个工具在 PyQt 中并没有包含。

撰写回答