我已经开始使用QtTest为我的PyQt5小部件创建UI测试,但遇到了以下困难:
-
为了加快速度,我的一些小部件只在可见时执行操作。像QtTest似乎使用不可见的小部件运行,相应的测试失败。
-
出于同样的原因,我无法测试使子窗口小部件可见的程序逻辑在某些条件下。
有没有办法让小部件在测试过程中可见?这种做法是否良好(例如。w.r.t.GitHub上的CI测试(,QtTest是一条路吗?
我曾尝试将pytest与pytest qt一起使用,但没有成功,因为我找不到合适的介绍或教程和我确实知道";用QTest和unittest测试PyQt GUI";。
下面是一个MWE,它由一个带有组合框的小部件mwe_qt_widget.MyWidget
、一个按钮和一个由其他两个子小部件更新的标签组成:
from PyQt5.QtWidgets import QComboBox, QWidget, QPushButton, QLabel, QHBoxLayout, QApplication
class MyWidget(QWidget):
def __init__(self, parent=None):
super(MyWidget, self).__init__(parent)
self.n = 0 # click counter
self.lbl = QLabel("default", self)
self.but = QPushButton("+ 1", self)
self.cmb = QComboBox(self)
self.cmb.addItems(["A", "B", "C"])
lay_h_main = QHBoxLayout(self)
lay_h_main.addWidget(self.cmb)
lay_h_main.addWidget(self.but)
lay_h_main.addWidget(self.lbl)
self.setLayout(lay_h_main)
self.cmb.currentIndexChanged.connect(
lambda: self.lbl.setText(self.cmb.currentText()+f" {self.n}"))
self.but.clicked.connect(self.update_label)
# --------------------------------------------------------------------------
def update_label(self):
"""count clicks and update label with current combobox text"""
if self.isVisible():
self.n += 1
self.lbl.setText(self.cmb.currentText()+f" {self.n}")
# ==============================================================================
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
mainw = MyWidget(None)
app.setActiveWindow(mainw)
mainw.show()
sys.exit(app.exec_())
此小部件使用以下测试设置进行测试。test_visibility()
和test_button()
失败,因为它们都要求被测试的小部件可见:
import sys, unittest
import mwe_qt_widget
from PyQt5 import QtTest, QtCore
from PyQt5.QtWidgets import QApplication
class WidgetTest(unittest.TestCase):
def init(self):
"""Instantiate widget-under-test and assert default settings"""
self.form = mwe_qt_widget.MyWidget()
self.assertEqual(self.form.cmb.currentText(), "A")
self.assertEqual(self.form.lbl.text(), "default")
# --------------------------------------------------------------------------
def test_button(self):
"""Test whether button click updates label"""
self.init()
QtTest.QTest.mouseClick(self.form.but, QtCore.Qt.LeftButton)
self.assertEqual(self.form.cmb.currentText(), "A")
self.assertEqual(self.form.lbl.text(), "A 1")
# --------------------------------------------------------------------------
def test_combobox(self):
"""Test whether combobox updates label"""
self.init()
QtTest.QTest.keyClick(self.form.cmb, QtCore.Qt.Key_PageDown)
QtTest.QTest.qWait(100)
self.assertEqual(self.form.cmb.currentText(), "B")
self.assertEqual(self.form.lbl.text(), "B 0")
# --------------------------------------------------------------------------
def test_visibility(self):
"""Test visibility of widget and subwidgets"""
self.init()
self.assertEqual(self.form.isVisible(), True)
self.assertEqual(self.form.cmb.isVisible(), True)
# ==============================================================================
if __name__ == '__main__':
app = QApplication(sys.argv) # Must construct a QApplication before a QWidget
unittest.main()
mainw = WidgetTest()
app.setActiveWindow(mainw)
mainw.show()
问题很简单:QWidget默认情况下是隐藏的,所以isVisible((将返回false,解决方案是调用init((中的show((方法使其可见:
class WidgetTest(unittest.TestCase):
def init(self):
"""Instantiate widget-under-test and assert default settings"""
self.form = mwe_qt_widget.MyWidget()
self.form.show()
self.assertEqual(self.form.cmb.currentText(), "A")
self.assertEqual(self.form.lbl.text(), "default")