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))

  1. 创建一个名为“自动化basiclayouts”的步骤。
  2. 识别basiclayouts示例中的控件,从而构建出相应的对象模型,并赋予上文中提到的对象名。
  3. 将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()
其中,CukeTest用于连接到远端的Worker,具有下面的方法:

JavaScript
Python
interface CukeTest {
    connect(options: ClientConnectOptions): Promise<IRemoteAuto>
}
def sync_auto(options: ClientConnectOptions) -> AutoContextManager
通过connect方法返回的auto实例,您可以访问远程所有的自动化根对象:

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"
其中,mousekeyboardscreen与本地的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"
例如,下面的方法设置了每个操作的1秒慢动作:

JavaScript
Python
auto.runSettings.set({slowMo: 1000});
auto.runSettings.set({"slowMo":500, "reportSteps": True})

results matching ""

    No results matching ""