QCoreApplication.postEvent(receiver, event) 只用输入函数给出好的结果

QCoreApplication.postEvent(receiver, event) give good result only with input function

对一段代码后面的部分进行单体测试(我用...替换掉不需要的东西来简化)

from PyQt5.QtWidgets import QWidget, QLineEdit

// ...

class Controller(QWidget):
    def __init__(self, ...)
        // ...
        self.line_edit_name = QLineEdit()
        // ...
    def display_parameters(self, name, ...)
        self.line_edit_name.setText(name)
            self.line_edit_name.setReadOnly(False)
            self.line_edit_name.returnPressed.connect(
                partial(self.update_name, ...))
    def update_name(self, ...):
        // ...

我使用这段代码使用 unittest 进行测试:

from PyQt5 import QtCore, QtGui
from PyQt5.QtCore import QCoreApplication, QEvent
// ...
a = Controller()
a.line_edit_name.setText("Shakespeare")
keyEvent = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, QtCore.Qt.Key_Return, QtCore.Qt.NoModifier)
QCoreApplication.postEvent(a.line_edit_name, keyEvent)
// ...

它在调试阶段工作得非常好(我经常使用 input('foo') 来反省并逐步查看发生了什么)... 但是如果我删除 input 函数它不再起作用了!!!!

总结: 以下脚本给出了正确的结果

    a = Controller()
    a.line_edit_name.setText("Shakespeare")
    keyEvent = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, QtCore.Qt.Key_Return, QtCore.Qt.NoModifier)
    QCoreApplication.postEvent(a.line_edit_name, keyEvent)
    input("foo")
    //...

以下不

    a = Controller()
    a.line_edit_name.setText("Shakespeare")
    keyEvent = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, QtCore.Qt.Key_Return, QtCore.Qt.NoModifier)
    QCoreApplication.postEvent(a.line_edit_name, keyEvent)
    // ...

因为单元测试是在持续集成期间自动完成的,所以我们不能使用输入功能。为什么会出现这个结果,没有输入功能怎么办?

编辑: 通过进行各种测试,我认为 input() 函数只允许进程在下一个命令之前完成。我在 QCoreApplication.postEvent(a.line_edit_name, keyEvent) 之后尝试代替 input("foo")threading.Event().wait(1)time.sleep(1) 但没有成功...

在 Qt 中,发送事件和调用与信号关联的槽的任务是异步的,所以不要指望立即得到响应,但你必须等待。在这种情况下,您必须使用 QTest.qWait.

既然你没有提供MRE,那我就简单演示一下:

from functools import partial

from PyQt5.QtCore import QCoreApplication, QEvent, Qt
from PyQt5.QtGui import QKeyEvent
from PyQt5.QtWidgets import QApplication, QFormLayout, QLineEdit, QWidget
from PyQt5.QtTest import QTest


class Controller(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.current_name = ""
        self.line_edit_name = QLineEdit()
        lay = QFormLayout(self)
        lay.addRow("name", self.line_edit_name)

    def display_parameters(self, name):
        self.line_edit_name.setText(name)
        self.line_edit_name.setReadOnly(False)
        self.line_edit_name.returnPressed.connect(partial(self.update_name, name))

    def update_name(self, name):
        self.current_name = name


def test_controller():
    app = QApplication([])

    a = Controller()
    a.display_parameters("Foo")

    assert a.current_name != "Foo"

    keyEvent = QKeyEvent(QEvent.KeyPress, Qt.Key_Return, Qt.NoModifier)
    QCoreApplication.postEvent(a.line_edit_name, keyEvent)
    # QTest.keyClick(a.line_edit_name, Qt.Key_Return)

    QTest.qWait(1000)

    assert a.current_name == "Foo"


test_controller()

另一方面,如果你想做测试,那么除了你可以使用 pytest-qt 之外,最好使用已经有几个简化功能的 QtTest 子模块。