当被测小部件必须可见才能工作时,PyQt5 下的 QtTest 失败
QtTest under PyQt5 fails when widgets-under-test have to be visible to work
我已经开始使用 QtTest 为我的 PyQt5 小部件创建 UI 测试,但是 运行
以下困难:
为了加快速度,我的一些小部件只在可见时执行操作。作为
似乎 QtTest 运行s 带有不可见的小部件,相应的测试失败。
出于同样的原因,我无法测试使 subwidget 可见的程序逻辑
在特定条件下。
有没有办法让小部件在测试期间可见?这是好的做法吗(例如
w.r.t。 CI 在 GitHub 上测试),QtTest 是正确的选择吗?
我尝试将 pytest 与 pytest-qt 一起使用但没有成功,因为我找不到合适的介绍或
教程,我确实知道 "Test PyQt GUIs with QTest and unittest"。
下面是一个 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()
问题很简单:QWidgets默认是隐藏的,所以isVisible()会returnfalse,解决方法是调用init()中的show()方法使其可见:
class WidgetTest(unittest.TestCase):
def init(self):
"""Instantiate widget-under-test and assert default settings"""
self.form = mwe_qt_widget.MyWidget()
<b>self.form.show()</b>
self.assertEqual(self.form.cmb.currentText(), "A")
self.assertEqual(self.form.lbl.text(), "default")
我已经开始使用 QtTest 为我的 PyQt5 小部件创建 UI 测试,但是 运行 以下困难:
为了加快速度,我的一些小部件只在可见时执行操作。作为 似乎 QtTest 运行s 带有不可见的小部件,相应的测试失败。
出于同样的原因,我无法测试使 subwidget 可见的程序逻辑 在特定条件下。
有没有办法让小部件在测试期间可见?这是好的做法吗(例如 w.r.t。 CI 在 GitHub 上测试),QtTest 是正确的选择吗?
我尝试将 pytest 与 pytest-qt 一起使用但没有成功,因为我找不到合适的介绍或 教程,我确实知道 "Test PyQt GUIs with QTest and unittest"。
下面是一个 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()
问题很简单:QWidgets默认是隐藏的,所以isVisible()会returnfalse,解决方法是调用init()中的show()方法使其可见:
class WidgetTest(unittest.TestCase):
def init(self):
"""Instantiate widget-under-test and assert default settings"""
self.form = mwe_qt_widget.MyWidget()
<b>self.form.show()</b>
self.assertEqual(self.form.cmb.currentText(), "A")
self.assertEqual(self.form.lbl.text(), "default")