Qt的远程自动化
CukeTest为Qt应用提供了远程执行的自动化解决方案。这意味着,CukeTest可以在一台电脑上运行,同时控制在另一台电脑上的Qt应用。例如,您可能会在Windows环境下运行CukeTest,而在Linux环境下执行Qt应用,通过远程调用协议实现这两者之间的交互。 更深入的远程自动化细节,请参考远程自动化文档。
以下为远程自动化的脚本示例:
JavaScript
Python
const { CukeTest } = require('cuketest');
const { setDefaultTimeout, Given, When, Then } = require('cucumber');
let QtAuto, modelQt;
setDefaultTimeout(20 * 1000);
BeforeAll(async function () {
//连接到远端Worker
let auto = await CukeTest.connect({
wsEndpoint: 'ws://192.168.1.5:3131/ws'
});
//获得远程的QtAuto对象
QtAuto = auto.qtAuto;
const { runSettings: RunSettings } = auto;
//设置慢速执行
await RunSettings.set({ slowMo: 500 });
//加载模型
let modelQt = await qtauto.loadModel('./basiclayouts.tmodel');
let capabilities = await auto.capabilities();
let homeDir = capabilities.homePath; // "C:\\Program Files\\LeanPro\\CukeTest"
let qtAppPath = [ // 针对系统不同传入多个启动路径,会自动选择可用的路径
`${homeDir}/bin/basiclayouts`, // Linux
`${homeDir}\\bin\\basiclayouts.exe`, // Windows
'/Applications/CukeTest.app/Contents/Frameworks/basiclayouts', // Mac
]
await modelQt.getApplication("basiclayouts").exists(10);
})
AfterAll(async function () {
//点击 "OK",退出应用
await modelQt.getButton("OK").click();
await modelQt.getApplication("basiclayouts").quit()
});
Given("自动化basiclayouts", async function () {
//点击 "Button_1"
await modelQt.getButton("Button_1").click();
//点击 "Edit"
await modelQt.getEdit("Edit").click(92, 11);
//设置控件值为"aabbcc"
let edit = modelQt.getEdit("Edit");
await modelQt.getEdit("Edit").set("something");
//点击 "Edit1"
await modelQt.getEdit("Edit1").click(297, 10);
//设置控件值为"asdf"
await modelQt.getEdit("Edit1").set("something else");
//增加 SpinBox "SpinBox"
await modelQt.getSpinBox("SpinBox").increment();
//增加 SpinBox "SpinBox"
await modelQt.getSpinBox("SpinBox").increment();
let snapshot = await modelQt.getSpinBox("SpinBox").takeScreenshot();
this.attach(snapshot, "image/png");
});
from auto.sync_api import sync_auto
from pytest_bdd import scenarios, given, when, then, parsers
from pytest_html import extras
import pytest
scenarios("../features")
@pytest.fixture(scope="session")
def remote_worker():
with sync_auto("ws://192.168.1.5:3131/ws") as auto:
RunSettings = auto.runSettings
QtAuto = auto.qtAuto
RunSettings.set({"slowMo":500, "reportSteps": True})
modelQt = QtAuto.loadModel('models/model.tmodel')
capabilities = auto.capabilities()
install_path = capabilities['homePath'] # "C:\\Program Files\\LeanPro\\CukeTest"
QtAuto.launchQtProcessAsync([ # 针对系统不同传入多个启动路径,会自动选择可用的路径
f"{install_path}/bin/basiclayouts", # Linux
f"{install_path}\\bin\\basiclayouts.exe", # Windows
f"/Applications/CukeTest.app/Contents/Frameworks/basiclayouts" # Mac
])
modelQt.getApplication("basiclayouts").exists(10)
# 在测试运行之前的建立远程链接并启动应用(在 yield 之前的部分)
yield auto
# 在测试函数运行之后执行清理工作(在 yield 之后的部分)
modelQt.getButton("OK").click()
modelQt.getApplication("basiclayouts").quit()
@pytest.fixture(scope="session")
def modelQt(remote_worker):
model = remote_worker.qtAuto.loadModel('models/model.tmodel')
return model
@given("自动化basiclayouts")
def automated_basiclayouts(modelQt):
#点击 "Button_1"
modelQt.getButton("Button_1").click()
#点击 "Edit"
modelQt.getEdit("Edit").click(92, 11)
#设置控件值为"aabbcc"
edit = modelQt.getEdit("Edit")
modelQt.getEdit("Edit").set("something")
#点击 "Edit1"
modelQt.getEdit("Edit1").click(297, 10)
#设置控件值为"asdf"
modelQt.getEdit("Edit1").set("something else")
#增加 SpinBox "SpinBox"
modelQt.getSpinBox("SpinBox").increment()
#增加 SpinBox "SpinBox"
modelQt.getSpinBox("SpinBox").increment()
snapshot = modelQt.getSpinBox("SpinBox").takeScreenshot()
extra.append(extras.image(snapshot))
- 创建一个名为“自动化basiclayouts”的步骤。
- 识别basiclayouts示例中的控件,从而构建出相应的对象模型,并赋予上文中提到的对象名。
- 将basiclayouts的可执行文件路径更新为远程机器上的相应路径,并将wsEndpoint属性设置为远程机器的网络地址。
在进行远程自动化之前,请确保已在远程电脑上启动了Worker服务。您可以在远程电脑中运行cuke worker
命令来启动。
值得注意的是,您可以通过本地录制来生成上述代码。在代码生成后,进行简单的修改便可在远程环境中执行。
下面展示了本地录制生成的操作代码及其修改后的版本:
原始本地录制代码:
JavaScript
Python
const { RunSettings } = require("leanpro.common");
const { QtAuto } = require("leanpro.qt");
(async () => {
await RunSettings.set({slowMo: 1000, reportSteps: true});
let modelQt = QtAuto.loadModel(__dirname + "/recording_2.tmodel");
await QtAuto.launchQtProcessAsync("C:\\Program Files\\LeanPro\\CukeTest\\bin\\basiclayouts.exe");
await modelQt.getApplication("basiclayouts").exists(10);
await modelQt.getButton("Button_1").click();
await modelQt.getWindow("Basic_Layouts").close();
await modelQt.getApplication("basiclayouts").quit();
})();
import os
from leanproAuto import RunSettings, QtAuto
def recording():
RunSettings.set({"slowMo": 1000, "reportSteps": True})
modelQt = QtAuto.loadModel(os.path.dirname(os.path.realpath(__file__)) + "/recording.tmodel")
QtAuto.launchQtProcessAsync("C:\\Program Files\\LeanPro\\CukeTest\\bin\\basiclayouts.exe")
modelQt.getApplication("basiclayouts").exists(10)
modelQt.getButton("Button_1").click()
modelQt.getWindow("Basic_Layouts").close()
modelQt.getApplication("basiclayouts").quit()
if __name__ == "__main__":
recording()
JavaScript
Python
const { CukeTest } = require("cuketest");
(async () => {
// 建立远程连接,并获取远程自动化对象
let auto = await CukeTest.connect({
wsEndpoint: 'ws://192.168.3.58:3131/ws'
});
const { runSettings: RunSettings } = auto;
const { qtAuto: QtAuto } = auto;
// 以下为原先的本地代码,无需修改
await RunSettings.set({slowMo: 1000, reportSteps: true});
let modelQt = await QtAuto.loadModel(__dirname + "/recording_1.tmodel");
await QtAuto.launchQtProcessAsync("C:\\Program Files\\LeanPro\\CukeTest\\bin\\basiclayouts.exe");
await modelQt.getApplication("basiclayouts").exists(10);
await modelQt.getButton("Button_1").click();
await modelQt.getWindow("Basic_Layouts").close();
await modelQt.getApplication("basiclayouts").quit();
auto.close();
})();
import os
from auto.sync_api import sync_auto
def recording():
# 建立远程连接,并获取远程自动化对象
with sync_auto("ws://192.168.3.58:3131/ws") as auto:
RunSettings = auto.runSettings
QtAuto = auto.qtAuto
# 以下为原先的本地代码,无需修改
RunSettings.set({"slowMo": 1000, "reportSteps": True})
modelQt = QtAuto.loadModel(os.path.dirname(os.path.realpath(__file__)) + "/recording.tmodel")
QtAuto.launchQtProcessAsync("C:\\Program Files\\LeanPro\\CukeTest\\bin\\basiclayouts.exe")
modelQt.getApplication("basiclayouts").exists(10)
modelQt.getButton("Button_1").click()
modelQt.getWindow("Basic_Layouts").close()
modelQt.getApplication("basiclayouts").quit()
if __name__ == "__main__":
recording()
JavaScript
Python
interface CukeTest {
connect(options: ClientConnectOptions): Promise<IRemoteAuto>
}
def sync_auto(options: ClientConnectOptions) -> AutoContextManager
JavaScript
Python
interface IRemoteAuto {
mouse: IMouse;
keyboard: IKeyboard;
screen: IScreen;
qtauto: IQtAuto;
runSettings: IRunSettings;
close();
}
class Auto(SyncContextManager):
def mouse() -> Mouse
def keyboard() -> Keyboard
def screen() -> Screen
def util() -> Util
def runSettings() -> RunSettings
def winAuto() -> WinAuto
def qtAuto() -> QtAuto
def cuketest() -> CukeTest
def visual() -> Visual
def capabilities() -> "any"
mouse
、keyboard
、screen
与本地的Mouse、Keyboard、Screen对象相对应。qtauto
则与本地的QtAuto对象对应,它们均提供类似的接口。runSettings
与本地的RunSettings对象相对应,您可以通过set和get方法分别设置和获取其值。
JavaScript
Python
interface IRunSettingsOptions {
defaultTimeout?: number;
slowMo?: number;
}
interface IRunSettings {
set(setting: IRunSettingsOptions): Promise<void>;
get(): Promise<IRunSettingsOptions>;
}
class RunSettingOptions:
defaultTimeout: int
slowMo: int
reportSteps: bool
class RunSettings(SyncBase):
defaultTimeout: int
slowMo: int
def set(options: TypedDict) -> "None"
def get(self) -> "any"
JavaScript
Python
auto.runSettings.set({slowMo: 1000});
auto.runSettings.set({"slowMo":500, "reportSteps": True})