PyQt & unittest - 测试信号和槽

发布于 2024-08-17 20:50:15 字数 350 浏览 4 评论 0原文

我有一个 pyqt 应用程序,正在为其编写单元测试,它严重依赖信号和槽。为了正确测试它,我必须检查是否发送了正确的信号。

最好的方法是什么?我看到 Qt 库有一个 QSignalSpy,但我在 PyQt 中找不到任何对此的引用。我能想到的唯一选择是模拟发射,例如,

import testedmodule

def myemit(signal):
    ....

testedmodule.QObject.emit = myemit

但我希望有更好的方法。

编辑:
我的模块作为线程运行,在这种情况下,启动线程后重写实例的发射不再起作用,因此我更新了上面的代码以反映这一点。

I have a pyqt application that I'm writing unit tests for, and it relies heavily on signals and slots. To properly test it, I have to check that the correct signals are sent.

What is the best way to do this? I see that the Qt library has a QSignalSpy, but I can't find any reference to this in PyQt. The only option I can think of is to mock emit, e.g.

import testedmodule

def myemit(signal):
    ....

testedmodule.QObject.emit = myemit

but I'm hoping there is a better way.

Edit:
My module is run as a thread, in that case overriding emit of an instance no longer worked after starting the thread so I updated the code above to reflect this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不羁少年 2024-08-24 20:50:15

您可以尝试将插槽连接到信号,准备测试,然后调用 qApp.processEvents() 让信号传播。但我不认为它是100%可靠的。

遗憾的是 QSignalSpy 确实不是 PyQt 的一部分。

You can try connecting a slot to your signal, prepare your test, then call qApp.processEvents() to let the signal propagate. But I don't think it's 100% reliable.

It's a pity that QSignalSpy is not part of PyQt indeed.

深居我梦 2024-08-24 20:50:15

这是我自己建议的更详细的版本,不一定是单元测试的最佳解决方案,但我认为遇到此问题的其他人会感兴趣:

由 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)并监视您的信号,直到
你胃不舒服:)

This is a more elaborate version of what I suggested myself, not necessarily the best solution for unittest, but I think it will be of interest to others that come across this:

Posted by Carlos Scheidegger on the pyqt mailing list (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

just call enableSignalDebugging(emitCall=foo) and spy your signals until
you're sick to your stomach :)

堇年纸鸢 2024-08-24 20:50:15

注意 QSignalSpy 可用作为QtTest.QSignalSpy在 PyQt5 中。

Note QSignalSpy is available as QtTest.QSignalSpy in PyQt5.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文