上下文
Qt5
我尝试为通过python3
(因此使用)编写的图形用户界面(GUI)创建集成测试pyqt5
。我使用pytest
插件pytest-qt
来测试 GUI。
我测试了很大程度上受此问题启发的 GUI ,因此该命令pytest -v -s
运行良好。
由于我的存储库是 on Github
,我Travis-CI
用来执行我的集成测试。
错误
但是,当我继续前进Github
并启动Travis
测试时,有时会出现以下错误:
Exceptions caught in Qt event loop:
________________________________________________________________________________
Traceback (most recent call last):
File "/home/travis/build/XXXX/Test/GUI_test.py", line 29, in handle_dialog
yes_button = messagebox.button(QtWidgets.QMessageBox.Yes)
AttributeError: 'Example' object has no attribute 'button'
MWE
我使用我的 git 存储库中包含的以下文件在 MWE 中重现此错误:
用python编写的GUI GUI.py
:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QCoreApplication, Qt, QObject
from PyQt5.QtGui import QIcon
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():
print('start')
app = QApplication(sys.argv)
imageViewer = Example()
return app, imageViewer
if __name__ == '__main__':
app, imageViewer =main_GUI()
rc= app.exec_()
print('App end is exit code {}'.format(rc))
sys.exit(rc)
pytest
用于创建 unittest的文件GUI_test.py
:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os, sys
from PyQt5 import QtGui, QtCore, QtWidgets, QtTest
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QCoreApplication, Qt, QObject
import pytest
import warnings
from pytestqt.plugin import QtBot, capture_exceptions
import mock
@pytest.fixture(scope="module")
def Viewer(request):
print(" SETUP GUI")
GUI= __import__('GUI')
app, imageViewer = GUI.main_GUI()
with capture_exceptions() as exceptions:
qtbotbis = QtBot(app)
QtTest.QTest.qWait(0.5 *1000)
yield app, imageViewer, qtbotbis
######### EXIT ##########
app.quitOnLastWindowClosed()
def handle_dialog():
messagebox = QtWidgets.QApplication.activeWindow()
yes_button = messagebox.button(QtWidgets.QMessageBox.Yes)
qtbotbis.mouseClick(yes_button, QtCore.Qt.LeftButton, delay=1)
QtCore.QTimer.singleShot(100, handle_dialog)
qtbotbis.mouseClick(imageViewer.btn_quit, QtCore.Qt.LeftButton, delay=1)
assert imageViewer.isHidden()
app.closeAllWindows()
app.quit()
app.exit()
app.closingDown()
QtTest.QTest.qWait(0.5 *1000)
with mock.patch.object(QApplication, "exit"):
app.exit()
assert QApplication.exit.call_count == 1
print("[Notice] So a mock.patch is used to count if the signal is emitted.")
print(" TEARDOWN GUI")
class Test_GUI_CXS() :
def test_buttons(self, Viewer, caplog):
app, mainWindow, qtbot = Viewer
qtbot.mouseClick( mainWindow.btn_prt, QtCore.Qt.LeftButton )
控制 travis 作业的文件.travis.yml
(可以根据文档p32 处理图形窗口):
language: python
python:
- "3.7"
sudo: required
dist: bionic
jobs:
include:
- stage: test
name: PyTest-GUI
before_install:
- python -m pip install --upgrade pip
- pip install -r ./requirement.txt
- sudo apt-get install -y libdbus-1-3 libxkbcommon-x11-0 dzen2
install:
- "export DISPLAY=:99.0"
- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 1920x1200x24 -ac+extension GLX +render -noreset"
- sleep 3
before_script:
- "herbstluftwm &"
- sleep 1
script:
- pytest -s -v ./GUI_test.py
addons:
apt:
packages:
- x11-utils
- libxkbcommon-x11-0
- herbstluftwm
- xvfb
services: xvfb
以及包含所需库的文件requirement.txt
:
pyqt5
mock
pytest
pytest-qt
其他尝试
我尝试在调试模式下运行 travis 作业。因此,在通过ssh
安装所有依赖项连接后,我尝试运行该命令pytest
并得到相同的错误。
但是,如果我这样做了,herbstluftwm &
那么pytest
测试运行良好并且不会出现错误。因此,我假设herbstluftwm &
正常的travis作业上的命令有问题,但我不知道如何解决。
欢迎任何提示或帮助!