如何测试使用 exec_() 调用的自定义对话框窗口?

Posted

技术标签:

【中文标题】如何测试使用 exec_() 调用的自定义对话框窗口?【英文标题】:How to test a custom dialog window called using exec_()? 【发布时间】:2019-11-27 15:14:32 【问题描述】:

我正在尝试为我的项目编写系统测试。我有一个启动各种窗口的控制器类。但是,我似乎无法通过 qtbot 使用 exec 来控制 Windows 启动。

这是一个 MVCE:

from PyQt5.QtWidgets import *
from PyQt5 import QtGui
class Controller:
    def __init__(self):
        self.name = None
        self.a = WindowA(self)

    def launchB(self):
        self.b = WindowB(self)

        if self.b.exec_():
            self.name = self.b.getData()

class WindowA(QDialog):
    def __init__(self, controller):
        super(WindowA, self).__init__()
        self.controller = controller
        layout = QVBoxLayout()
        self.button = QPushButton('Launch B')
        self.button.clicked.connect(self.controller.launchB)
        layout.addWidget(self.button)
        self.setLayout(layout)
        self.show()

class WindowB(QDialog):
    def __init__(self, controller):
        super(WindowB, self).__init__()
        self.controller = controller
        layout = QVBoxLayout()
        self.le = QLineEdit()
        self.button = QPushButton('Save')
        self.button.clicked.connect(self.save)
        layout.addWidget(self.le)
        layout.addWidget(self.button)
        self.setLayout(layout)
        self.show()

    def getData(self):
        return self.le.text()

    def save(self):
        if self.le.text():
            self.accept()
            self.close()   
        else:
            self.reject()

from PyQt5.QtWidgets import QApplication

if __name__ == '__main__':

    import sys

    app = QApplication(sys.argv)
    window = Controller()
    sys.exit(app.exec_())

我想测试用户是否成功在 lineedit 中输入数据。在我的测试中,我能够成功单击 WindowA 中的按钮以启动 WindowB,但无法使用 keyClicks 在 lineedit 中输入数据。

这是测试:

def test_1(qtbot):
    control = Controller()
    qtbot.mouseClick(control.a.button, QtCore.Qt.LeftButton)

    qtbot.keyClicks(control.b.le, 'Test_Project')
    qtbot.mouseClick(control.b.button, QtCore.Qt.LeftButton)

    assert control.name == 'Test_Project'

【问题讨论】:

【参考方案1】:

问题是使用exec_()会阻塞所有同步任务直到窗口关闭,解决方案是使用QTimer异步启动剩余任务:

def test_1(qtbot):
    control = Controller()

    def on_timeout():
        qtbot.keyClicks(control.b.le, "Test_Project")
        qtbot.mouseClick(control.b.button, QtCore.Qt.LeftButton)

    QtCore.QTimer.singleShot(0, on_timeout)
    qtbot.mouseClick(control.a.button, QtCore.Qt.LeftButton)

    assert control.name == "Test_Project"

【讨论】:

受这个答案的启发,我使用过这种技术一两次,但我认为它偶尔会导致测试泄漏,以及在拆卸或设置期间发生错误(下一次测试) )。至少我建议您需要将QtCore.QCoreApplication.processEvents() 放在最后的assert 之前。还有qtbot.waitUntil(),大概比QTimer.singleShot()更安全……

以上是关于如何测试使用 exec_() 调用的自定义对话框窗口?的主要内容,如果未能解决你的问题,请参考以下文章

测试泊坞窗图像。使用 exec 轻松启动并获取日志

MFC - 如何从菜单主机调用对话框

使用 Qt Test 测试模式对话框

基于JQ的自定义弹窗组件

如何调用属于 PHP 类的自定义函数(wordpress do_action 样式)?

python导入同一目录下的自定义模块,出现ModuleNotFoundError