Я пытаюсь провести модульное тестирование GUI, написанного на Pyside2. Поскольку я не хочу, чтобы во время тестов отображались окна сообщений (что могло бы привести к остановке тестов при ожидании ввода данных пользователем), я подумал о исправлении QFileDialog
. Однако это приводит к тому, что тесты противоречивы. Я не смог найти какой-либо ресурс о том, как правильно смоделировать / исправить патч QFileDialog
, поэтому я не уверен, правильно ли я поступаю.
Поведение, которое я описал, воспроизводимо с двумя Сценарии ниже:
myapp.py - простой интерфейс с кнопкой, при нажатии на которую открывается диалоговое окно файла и записывается выбранное имя файла в метку.
import sys
from PySide2.QtWidgets import (QApplication, QFileDialog, QLabel, QMainWindow,
QPushButton, QWidget, QVBoxLayout)
class MyApp(QMainWindow):
def __init__(self):
super().__init__()
self.frame = QWidget(self)
self.setCentralWidget(self.frame)
main_layout = QVBoxLayout()
self.frame.setLayout(main_layout)
self.btn = QPushButton(self, text='Load file')
self.btn.clicked.connect(self.load_file)
main_layout.addWidget(self.btn)
self.label = QLabel(self, text='')
main_layout.addWidget(self.label)
def load_file(self):
query, _ = QFileDialog.getOpenFileName(self, 'Select input file')
if query:
self.label.setText('File loaded: ' + query)
else:
self.label.setText('File loaded: None')
if __name__ == '__main__':
app = QApplication()
ui = MyApp()
ui.show()
sys.exit(app.exec_())
test_myapp.py - два модульных теста, которые проверяют, правильно ли обновлена метка (в зависимости от того, вернул ли QFileDialog
пустую строку или нет).
import unittest
from unittest.mock import patch
from PySide2.QtWidgets import QApplication
from myapp import MyApp
class TestMyApp(unittest.TestCase):
@classmethod
def setUpClass(self):
self.app = QApplication()
def setUp(self):
self.ui = MyApp()
def tearDown(self):
self.ui.destroy()
def test_dialog_box_user_selected_a_file(self):
with patch('myapp.QFileDialog.getOpenFileName',
return_value=('somefile', None)) as dialog_mock:
self.ui.load_file()
self.assertEqual(self.ui.label.text(), 'File loaded: somefile')
def test_dialog_box_user_closed_dialog_without_selecting_a_file(self):
with patch('myapp.QFileDialog.getOpenFileName',
return_value=('', None)) as dialog_mock:
self.ui.load_file()
self.assertEqual(self.ui.label.text(), 'File loaded: None')
if __name__ == '__main__':
unittest.main()
Запуск тестов с python -m unittest test_myapp.py
приводит к (большей части времени):
AssertionError: 'File loaded: None' != 'File loaded: somefile'
- File loaded: None
? ^ ^
+ File loaded: somefile
? ^ ^^^^^
----------------------------------------------------------------------
Ran 2 tests in 0.013s
FAILED (failures=1)
И все же иногда тесты приводят к:
..
----------------------------------------------------------------------
Ran 2 tests in 0.013s
OK
Поскольку первый тест всегда проходит, мне кажется, что QFileDialog
исправляется успешно. Почему второй тест не может исправить это (по крайней мере, большую часть времени)? Если такого рода юнит-тестирование невозможно, есть ли другой способ проверить метод load_file
?