[英]Testing QML based app with pytest in python
我想測試我的 QML 前端代碼以及我的 Python 后端代碼(使用 PySide2),最好使用 Pytest,並且能夠像pytest-qt插件一樣發送keyClicks
, MouseClicks
和signals
。 我已經簽出pytest-qml ,但測試代碼是通過 QML 編寫的,然后僅通過 pytest 運行,但我想從 python 本身發送事件等,而不是 QML
基本上,具有這樣的 python 代碼:
"""
Slots, Signals, context class etc etc...
"""
app = QGuiApplication([])
engine = QQmlApplicationEngine()
engine.load(QUrl.fromLocalFile("main.qml"))
app.exec_()
和一個簡單的main.qml
文件,
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Window 2.2
import QtQuick.Controls 2.15
ApplicationWindow {
id: mywin
width: Screen.desktopAvailableWidth
height: Screen.desktopAvailableHeight
visible: true
FileDialog {
id: openDialog
title: "mydialog"
onAccepted: {
}
}
Button {
objectName: "mybtn"
width: 200
height: 200
id: btn
text: "hello"
onClicked: {
openDialog.open()
}
}
}
我想做(偽代碼)類似的事情
def test_file_open():
#Grab QQuickItem(btn)
#Send mouse event to click btn
#Send string to file dialog
# assert string sent == string selected
pytest-qt
插件可以工作,但函數采用QWidget
和 QML 處理QQuickItems
,據我所知,它不處理 QWidgets。
甚至有可能,或者我測試我的應用程序插槽等的唯一選擇是通過pytest-qml
嗎? 也許這是最簡單的方法,但也許還有其他選擇:)
編輯:
如果您使用import Qt.labs.platform 1.1
而不是import QtQuick.Dialogs 1.3
,並強制 QML不使用本機對話框,則只需更改
# assert myfiledialog.property("fileUrl").toLocalFile() == filename # uses QDialog
assert myfiledialog.property("currentFile").toLocalFile() == filename # using QLabs Dialog
然后使用來自已接受答案的代碼 rest 它將起作用,因此顯然它不使用本機對話框非常重要。
如果將來有其他人知道如何使用本機對話框並使用QtQuick.Dialogs 1.3
作為最初提出的問題,那就太好了:)。 但這對整體測試來說還是不錯的!
您可以使用相同的 API,因為 pytest-qt 基於 QtTest。 顯然你必須了解應用程序的結構,例如 FileDialog 只是一個 QObject,它只管理一個具有對話框的 QWindow,此外還管理項目相對於 windows 的位置。
import os
from pathlib import Path
from PySide2.QtCore import QUrl
from PySide2.QtQml import QQmlApplicationEngine
CURRENT_DIR = Path(__file__).resolve().parent
def build_engine():
engine = QQmlApplicationEngine()
filename = os.fspath(CURRENT_DIR / "main.qml")
url = QUrl.fromLocalFile(filename)
engine.load(url)
return engine
def main():
app = QGuiApplication([])
engine = build_engine()
app.exec_()
if __name__ == "__main__":
main()
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Dialogs 1.3
import QtQuick.Layouts 1.15
import QtQuick.Window 2.2
ApplicationWindow {
id: mywin
width: Screen.desktopAvailableWidth
height: Screen.desktopAvailableHeight
visible: true
FileDialog {
id: openDialog
objectName: "myfiledialog"
title: "mydialog"
onAccepted: {
}
}
Button {
id: btn
objectName: "mybtn"
width: 200
height: 200
text: "hello"
onClicked: {
openDialog.open();
}
}
}
import os
from PySide2.QtCore import QCoreApplication, QObject, Qt, QPointF
from PySide2.QtGui import QGuiApplication
from PySide2.QtQuick import QQuickItem
from PySide2.QtWidgets import QApplication
import pytest
from app import build_engine
@pytest.fixture(scope="session")
def qapp():
QCoreApplication.setOrganizationName("qapp")
QCoreApplication.setOrganizationDomain("qapp.com")
QCoreApplication.setAttribute(Qt.AA_DontUseNativeDialogs)
yield QApplication([])
def test_app(tmp_path, qtbot):
engine = build_engine()
assert QCoreApplication.testAttribute(Qt.AA_DontUseNativeDialogs)
with qtbot.wait_signal(engine.objectCreated, raising=False):
assert len(engine.rootObjects()) == 1
root_object = engine.rootObjects()[0]
root_item = root_object.contentItem()
mybtn = root_object.findChild(QQuickItem, "mybtn")
assert mybtn is not None
center = QPointF(mybtn.width(), mybtn.height()) / 2
qtbot.mouseClick(
mybtn.window(),
Qt.LeftButton,
pos=root_item.mapFromItem(mybtn, center).toPoint(),
)
qtbot.wait(1000)
qfiledialog = None
for window in QGuiApplication.topLevelWindows():
if window is not root_object:
qfiledialog = window
assert qfiledialog is not None, QGuiApplication.topLevelWindows()
file = tmp_path / "foo.txt"
file.touch()
filename = os.fspath(file)
for letter in filename:
qtbot.keyClick(qfiledialog, letter, delay=100)
qtbot.wait(1000)
qtbot.keyClick(qfiledialog, Qt.Key_Return)
qtbot.wait(1000)
myfiledialog = root_object.findChild(QObject, "myfiledialog")
assert myfiledialog is not None
assert myfiledialog.property("fileUrl").toLocalFile() == filename
注意:如果 filedialog 使用本機 window,測試可能會失敗,您可以使用 pyinput 之類的工具,但更簡單的選擇是使用 virtualenv。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.