PyQt单元测试:确保已创建QDialog

5

我有一个父级控件,有时会调用自定义QDialog来获取用户输入。如何编写单元测试以确保已调用对话框,并且它将正确处理输入?

这里是一个小例子:

from PyQt5.QtWidgets import QDialog, QVBoxLayout, QWidget, QLabel, QApplication
from PyQt5.Qt import pyqtSignal, QPushButton, pyqtSlot, QLineEdit
import sys


class PopupDialog(QDialog):
    result = pyqtSignal(str)

    def __init__(self):
        super().__init__()
        layout = QVBoxLayout(self)
        self.setLayout(layout)
        lbl = QLabel("That's not a full number! Try again?")
        layout.addWidget(lbl)
        self.field = QLineEdit(self)
        layout.addWidget(self.field)

        self.btn = QPushButton("Ok")
        self.btn.clicked.connect(self.on_clicked)
        layout.addWidget(self.btn)

    def on_clicked(self):
        value = self.field.text().strip()
        self.result.emit(value)
        self.close()


class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.init_UI()

    def init_UI(self):
        layout = QVBoxLayout()
        self.setLayout(layout)

        lbl = QLabel("Please provide a full number")
        layout.addWidget(lbl)

        self.counter_fld = QLineEdit(self)
        self.counter_fld.setText("1")
        layout.addWidget(self.counter_fld)

        self.btn = QPushButton("start")
        layout.addWidget(self.btn)
        self.btn.clicked.connect(self.on_clicked)

        self.field = QLabel()
        layout.addWidget(self.field)
        self.show()

    @pyqtSlot()
    def on_clicked(self):
        txt = self.counter_fld.text()
        self.dialog = None
        try:
            result = int(txt) * 100
            self.field.setText(str(result))
        except ValueError:
            self.dialog = PopupDialog()
            self.dialog.result.connect(self.catch_dialog_output)
            self.dialog.exec_()

    @pyqtSlot(str)
    def catch_dialog_output(self, value):
        self.counter_fld.setText(value)
        self.on_clicked()


def main():
    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

在这种情况下,我想编写一个单元测试,向self.field插入不同的值,然后测试它能否在插入整数时正常工作,但在插入字符串时调用PopupDialog。

(我知道我可以在没有对话框的情况下测试功能,并且对于此问题,实际上并不需要QDialog。我只是试图保持示例简单。基本线路是:我可以通过步骤获取单元测试直到创建弹出对话框,但如何测试它确实被创建,并与其交互以测试结果?)

#!/usr/bin/env Python3

import unittest
import temp2

class Test1(unittest.TestCase):
    @classmethod
    def setUpClass(self):
        self.w = temp2.Example()

    def testHappy(self):
        for i in [0,1,5]:
            self.w.counter_fld.setText(str(i))
            self.w.btn.click()
            value = self.w.field.text()
            self.assertEqual(value, str(i * 100))

    def testSad(self):
        for i in ["A", "foo"]:
            self.w.counter_fld.setText(str(i))
            self.w.btn.click()
            # now what?


if __name__ == "__main__":
    unittest.main()   

(我在Windows上使用Python3.6中的PyQt5。)

有什么我可以做/添加/解释以获得任何答案吗? - CodingCat
1个回答

5

有几种方法可以检查QDialog是否已创建:

1)打补丁到PopupDialog并验证是否已调用。

from unittest.mock import patch

@patch("temp2.PopupDialog")
def testPopupDialog(self, mock_dialog):
        self.w.counter_fld.setText(str("A"))
        self.w.btn.click()
        mock_dialog.assert_called_once()

2) 与PopupDialog进行交互可能需要更多的操作。

def testPopupDialogInteraction(self):
        self.w.counter_fld.setText(str("A"))
        self.w.btn.click()
        if hasattr(self.w.dialog, "field"):
            self.w.dialog.field.setText(str(1))
            self.w.dialog.btn.click()
            value = self.w.field.text()
            self.assertEqual(value, str(1 * 100))
        raise Exception("dialog not created")

另外,有一种更好的验证用户输入方式,即使用QRegExpValidator。请查看这个Stack Overflow答案

在目前的方法中,每当用户输入不合适的值时它都会继续创建一个弹出窗口,这会导致糟糕的用户体验(UX)。即使网站也使用验证器而不是弹出窗口。


谢谢您指出 mock 和 @patch,这正是我在寻找的!(是的,我知道在这种情况下弹出窗口毫无意义。我的实际弹出窗口会询问用户的选择,并且更加复杂,包括弹出窗口和调用它的情况。我只是想为此快速创建一个最小化可重现示例。) - CodingCat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接