使用 pytest 测试 pyqt 应用程序
testing pyqt application with pytest
我正在使用 pytest 及其 pytest-qt 插件测试 PyQt5 应用程序。
我创建了一个夹具来加载我的应用程序 class 然后我将其用于所有测试
到目前为止我有两个问题
- gui出现了,我不要了。
- 如果我编写更多测试,我最终会遇到分段错误,因为(我认为)打开的 gui 太多。
有什么想法吗?
pytest-qt 的文档非常基础,实际上有一个显示 GUI
的测试
一个最小的例子是:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QCoreApplication, QObject, Qt
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import *
class Example(QMainWindow):
def __init__(self, parent=None):
super().__init__()
self.initUI(self)
def initUI(self, MainWindow):
# centralwidget
MainWindow.resize(346, 193)
self.centralwidget = QtWidgets.QWidget(MainWindow)
# The Action to quit
self.toolb_action_Exit = QAction(QIcon("exit.png"), "Exit", self)
self.toolb_action_Exit.setShortcut("Ctrl+Q")
self.toolb_action_Exit.triggered.connect(self.close)
# The Button
self.btn_prt = QtWidgets.QPushButton(self.centralwidget)
self.btn_prt.setGeometry(QtCore.QRect(120, 20, 89, 25))
self.btn_prt.clicked.connect(lambda: self.doPrint())
self.btn_quit = QtWidgets.QPushButton(self.centralwidget)
self.btn_quit.setGeometry(QtCore.QRect(220, 20, 89, 25))
self.btn_quit.clicked.connect(lambda: self.close())
# The textEdit
self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
self.textEdit.setGeometry(QtCore.QRect(10, 60, 321, 81))
# Show the frame
MainWindow.setCentralWidget(self.centralwidget)
# self.show()
def doPrint(self):
print("TEST doPrint")
def closeEvent(self, event):
# Ask a question before to quit.
self.replyClosing = QMessageBox.question(
self,
"Message",
"Are you sure to quit?",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No,
)
if self.replyClosing == QMessageBox.Yes:
event.accept()
else:
event.ignore()
def main_GUI():
app = QApplication(sys.argv)
imageViewer = Example()
imageViewer.show()
return app, imageViewer
if __name__ == "__main__":
app, imageViewer = main_GUI()
rc = app.exec_()
print("App end is exit code {}".format(rc))
sys.exit(rc)
测试:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import pytest
from PyQt5 import QtCore, QtGui, QtTest, QtWidgets
from PyQt5.QtCore import QCoreApplication, QObject, Qt
from PyQt5.QtWidgets import *
from pytestqt.plugin import QtBot
GUI = __import__("GUI")
@pytest.fixture(scope="module")
def qtbot_session(qapp, request):
print(" SETUP qtbot")
result = QtBot(qapp)
with capture_exceptions() as exceptions:
yield result
print(" TEARDOWN qtbot")
@pytest.fixture(scope="module")
def Viewer(request):
print(" SETUP GUI")
app, imageViewer = GUI.main_GUI()
qtbotbis = QtBot(app)
QtTest.QTest.qWait(0.5 * 1000)
return app, imageViewer, qtbotbis
def test_interface(Viewer):
print(" beginning ")
app, imageViewer, qtbot = Viewer
assert imageViewer.textEdit.toPlainText() == ''
如果您不想显示 GUI,那么一个可能的解决方案是使用 Qt::WA_DontShowOnScreen
标志,为此您必须执行以下操作:
- 删除 main_GUI 中的
imageViewer.show()
。
- 在 Viewer fixture 中添加
imageViewer.setAttribute(Qt.WA_DontShowOnScreen, True)
和 imageViewer.show()
。
另一种选择是在 pytest.ini
:
中将环境变量 QT_QPA_PLATFORM
设置为 "offscreen"
env =
D:QT_QPA_PLATFORM=offscreen
如果使用 pyproject.toml
,将如下所示:
[tool.pytest.ini_options]
env = [
"D:QT_QPA_PLATFORM=offscreen"
]
我发现已接受的解决方案并不完全有效(例如,您的鼠标仍处于移动状态,点击了某些内容,并且菜单栏菜单仍然出现)。
此解决方案似乎没有该问题。
我正在使用 pytest 及其 pytest-qt 插件测试 PyQt5 应用程序。
我创建了一个夹具来加载我的应用程序 class 然后我将其用于所有测试
到目前为止我有两个问题
- gui出现了,我不要了。
- 如果我编写更多测试,我最终会遇到分段错误,因为(我认为)打开的 gui 太多。
有什么想法吗? pytest-qt 的文档非常基础,实际上有一个显示 GUI
的测试一个最小的例子是:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QCoreApplication, QObject, Qt
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import *
class Example(QMainWindow):
def __init__(self, parent=None):
super().__init__()
self.initUI(self)
def initUI(self, MainWindow):
# centralwidget
MainWindow.resize(346, 193)
self.centralwidget = QtWidgets.QWidget(MainWindow)
# The Action to quit
self.toolb_action_Exit = QAction(QIcon("exit.png"), "Exit", self)
self.toolb_action_Exit.setShortcut("Ctrl+Q")
self.toolb_action_Exit.triggered.connect(self.close)
# The Button
self.btn_prt = QtWidgets.QPushButton(self.centralwidget)
self.btn_prt.setGeometry(QtCore.QRect(120, 20, 89, 25))
self.btn_prt.clicked.connect(lambda: self.doPrint())
self.btn_quit = QtWidgets.QPushButton(self.centralwidget)
self.btn_quit.setGeometry(QtCore.QRect(220, 20, 89, 25))
self.btn_quit.clicked.connect(lambda: self.close())
# The textEdit
self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
self.textEdit.setGeometry(QtCore.QRect(10, 60, 321, 81))
# Show the frame
MainWindow.setCentralWidget(self.centralwidget)
# self.show()
def doPrint(self):
print("TEST doPrint")
def closeEvent(self, event):
# Ask a question before to quit.
self.replyClosing = QMessageBox.question(
self,
"Message",
"Are you sure to quit?",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No,
)
if self.replyClosing == QMessageBox.Yes:
event.accept()
else:
event.ignore()
def main_GUI():
app = QApplication(sys.argv)
imageViewer = Example()
imageViewer.show()
return app, imageViewer
if __name__ == "__main__":
app, imageViewer = main_GUI()
rc = app.exec_()
print("App end is exit code {}".format(rc))
sys.exit(rc)
测试:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import pytest
from PyQt5 import QtCore, QtGui, QtTest, QtWidgets
from PyQt5.QtCore import QCoreApplication, QObject, Qt
from PyQt5.QtWidgets import *
from pytestqt.plugin import QtBot
GUI = __import__("GUI")
@pytest.fixture(scope="module")
def qtbot_session(qapp, request):
print(" SETUP qtbot")
result = QtBot(qapp)
with capture_exceptions() as exceptions:
yield result
print(" TEARDOWN qtbot")
@pytest.fixture(scope="module")
def Viewer(request):
print(" SETUP GUI")
app, imageViewer = GUI.main_GUI()
qtbotbis = QtBot(app)
QtTest.QTest.qWait(0.5 * 1000)
return app, imageViewer, qtbotbis
def test_interface(Viewer):
print(" beginning ")
app, imageViewer, qtbot = Viewer
assert imageViewer.textEdit.toPlainText() == ''
如果您不想显示 GUI,那么一个可能的解决方案是使用 Qt::WA_DontShowOnScreen
标志,为此您必须执行以下操作:
- 删除 main_GUI 中的
imageViewer.show()
。 - 在 Viewer fixture 中添加
imageViewer.setAttribute(Qt.WA_DontShowOnScreen, True)
和imageViewer.show()
。
另一种选择是在 pytest.ini
:
QT_QPA_PLATFORM
设置为 "offscreen"
env =
D:QT_QPA_PLATFORM=offscreen
如果使用 pyproject.toml
,将如下所示:
[tool.pytest.ini_options]
env = [
"D:QT_QPA_PLATFORM=offscreen"
]
我发现已接受的解决方案并不完全有效(例如,您的鼠标仍处于移动状态,点击了某些内容,并且菜单栏菜单仍然出现)。
此解决方案似乎没有该问题。