Модульный тест PyQt, что QDialog создан - PullRequest
4 голосов
/ 08 марта 2019

У меня есть родительский виджет, который в некоторых случаях вызывает пользовательский 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 для целых чисел, но при вставке строки вызывается 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()   

(я использую PyQt5 в Python3.6 для Windows.)

1 Ответ

3 голосов
/ 18 марта 2019

Ну, есть несколько способов проверить, создан ли 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. Проверьте это SO ответ

В настоящем методе он будет продолжать создавать всплывающее окно каждый раз, когда пользователь вводит неправильное значение, и создает плохой пользовательский интерфейс (UX). Даже веб-сайты используют валидаторы вместо всплывающих окон.

...