• 演练:创建Windows自动化测试
    • 1. 新建项目
    • 2. 编辑用例
    • 3. 获取应用控件
    • 4. 完善自动化代码
    • 5. 实现所有自动化步骤
    • 4. 运行

    演练:创建Windows自动化测试

    本文演示如何使用Node.js为Windows 10记事本(Notepad)创建自动化脚本。 您还将了解如何为Windows应用程序创建对象模型,以及如何使用Windows自动化API。

    在本演练中,我们将:

    • 创建描述自动化步骤的BDD场景
    • 侦测记事本控件并将测试对象添加到对象模型
    • 实现自动化代码
    • 调试并运行脚本以获取报告

    环境要求

    • 操作系统: Windows 10
    • 被测应用:Windows 10 自带记事本

    1. 新建项目

    1.打开CukeTest,单击“文件” - >“新建项目”

    2.将“NotepadTesting”设置为项目名称,并选择“Windows”项目模板,同时指定项目路径,然后单击“创建”以创建项目。

    image.png

    2. 编辑用例

    打开 feature1.feature 文件,在【可视】界面中输入场景描述内容。

    image.png

    有关如何使用“Visual”视图编辑要素文件的更多信息,可以参考演练:编辑Feature文件

    对应的【文本】视图内容为:

    1. # language: zh-CN
    2. 功能: 记事本应用程序自动化
    3. 自动执行Windows 10 Notepad应用程序以进行测试
    4. 场景: 编辑内容并保存
    5. 假如打开Windows记事本应用
    6. 当在记事本中输入文本"hello world"
    7. 并且选择[文件] -> [保存]以显示文件保存对话框
    8. 同时输入文件名"helloworld.txt"并单击[确定]
    9. 那么文件应该保存成功
    10. 场景: 更改记事本字体
    11. 假如打开Windows记事本应用
    12. 当选择[格式] -> [字体...]打开字体对话框
    13. 并且从[字体]下拉框中选择[Arial]字体
    14. 同时单击[确定]按钮以关闭[字体...]对话框
    15. 那么字体应有设置为[Arial]

    3. 获取应用控件

    自动化Windows应用程序时,“测试对象”用于标识窗口控件。 每个测试对象都包含一组用于定位控件的属性和规则。 测试对象信息存储在对象模型文件中(或缩写为“模型文件”),以“.tmodel”结尾。 CukeTest中的模型管理器用于创建和管理模型文件。 以下是有关如何侦测并向模型添加对象的步骤:

    点击【添加对象】按钮演练:创建Windows自动化测试 - 图3,开始识别元素,在要操作的对象上点击鼠标,识别元素控件。如果控件成功侦察,则显示要添加的控件及其属性。然后单击【添加到模型】演练:创建Windows自动化测试 - 图4 按钮将其添加到对象模型中。

    现在请按照以下步骤创建模型:

    • 点击step_definitions\model1.tmodel,会使用模型管理器打开此文件。

    image.png

    • 打开记事本,侦测以下控件列表,并将它们添加到模型中,同时将它们命名为下面的“对象名称”列:
    文本控件类型对象名称
    "File"MenuItem文件
    "Save"MenuItem保存
    "Format"MenuItem格式
    "Font…"MenuItem字体
    ""Document文本编辑器

    提示一个侦测的技巧,要侦测“保存”菜单项,单击“文件”菜单时先按Ctrl键,这样点击就不会触发对象添加对话框显示,然后单击“保存”时释放Ctrl键,这时候会显示对话框。

    • 通过单击“格式” - >“字体…”菜单打开“字体”对话框,侦测并添加以下控件列表,并将它们添加到模型中。
    TextControl TypeObject Name
    "Arial"ListItemArial
    "确定"Button确定
    • 打开文件保存对话框,侦测并添加以下控件列表,并将它们添加到模型中:
    TextControl TypeObject Name
    ""Edit文件名
    "保存"Button保存按钮
    • 侦测完成后,有些属性需要修改,适合自动化的场景,例如侦测的时候添加的Notepad窗体对象会自动加上Title,因为Title随着文件名变化而变化,它不适合作为Notepad窗体的唯一性标识,所以在窗体上点右键选择删除:

    演练:创建Windows自动化测试 - 图6

    删除后它会作为其它属性存在:

    演练:创建Windows自动化测试 - 图7

    • 可以将缺省对象名改为有意义的名字,虽然这不会影响使用,但是可以让对象更易于管理,可读性更强。例如将Notepad主窗口设为“Notepad”,文件对话框窗口设为“File Dialog”,字体对话框设为“Font Dialog”。

      添加所有这些元素后,您的模型应如下所示:

    image.png

    4. 完善自动化代码

    • 打开 step_definations\definitions1.js 文件,点击 step 后面的灰色按钮,生成自动化脚本样例。

    演练:创建Windows自动化测试 - 图9

    请注意,现在步骤文本旁边的按钮是橙色,这意味着这些步骤具有匹配的步骤定义功能,但它们尚未实现。

    您可能还注意到,模型加载代码已添加到此文件中,因此在创建项目时的代码中,您可以直接使用此模型变量来访问这些对象。

    现在您可以打开model1.tmodel文件,从模型树中选择一个对象,选择“Actions / Properties”选项卡,然后从列表中复制该方法并将它们添加到脚本中。

    此外您还可以通过拖拽某个方法或者某个测试对象到代码编辑器,来生成对应的代码。

    • 要实现步骤定义,首先要实现“打开给定记事本应用程序”步骤,您可以使用“Util.launchProcess”API来启动记事本过程:

    ```javascriptGiven(/^打开Windows记事本应用$/, async function () { Util.launchProcess('c:\Windows\notepad.exe');});

    • 编写代码后,可以通过右键单击该步骤来测试它,然后单击步骤工具栏上的“运行此步骤”按钮:

    演练:创建Windows自动化测试 - 图10

    这只是为了调试目的而运行的步骤,如果成功,你的记事本应该启动。

    • 在实现其余步骤之前,我们应该添加Hook函数,以便在脚本启动时最小化CukeTest窗口,并在运行完成时恢复CukeTest窗口,我们可以在BeforeAllAfterAll钩子中实现这一点。 添加文件“support / hooks.js”,并输入以下内容:
    1. const {BeforeAll, AfterAll, setDefaultTimeout} = require('cucumber')
    2. const cuketest = require('cuketest');
    3. setDefaultTimeout(20 * 1000);
    4. BeforeAll(async function() {
    5. await cuketest.minimize();
    6. await cuketest.delay(1000);
    7. })
    8. AfterAll(async function () {
    9. await cuketest.delay(1000);
    10. await cuketest.maximize();
    11. })

    在hooks.js中,我们将步骤超时设置为20秒而不是默认的5秒,这对于Windows自动化脚本来说有点短。 另外,在BeforeAll中,我们在运行任何场景之前最小化CukeTest窗口,等待1秒直到最小化实际生效,这样在执行自动化操作时它不会干扰被测应用程序的UI。

    5. 实现所有自动化步骤

    • 现在我们可以实现第二步:
    1. 当在记事本中输入文本"hello world"

    在此步骤定义函数sub中,将参数名称更改为“text”,并将“Text Editor”对象从Model Manager拖到该函数中,选择set方法,并在其中填入参数“text”,代码如下:

    1. When(/^在记事本中输入文本"([^"]*)"$/, async function (text) {
    2. await model.getDocument("Text Editor").set(text);
    3. });

    假设您已经打开了一个记事本,您现在可以右键单击该步骤文本,并选择“运行此步骤”,就像您执行第一步一样,它将最小化CukeTest,将记事本内容设置为“hello world”,然后 恢复CukeTest窗口。 如果此步骤成功运行,您可以类似地添加其余步骤。

    • 为节省篇幅,我粘贴下面的所有definitions1.js代码:
    1. ```javascript
    2. const { Given, When, Then } = require('cucumber');
    3. const { TestModel, Auto } = require('leanpro.win');
    4. const { Util } = require('leanpro.common');
    5. const fs = require('fs');
    6. const cuketest = require('cuketest')
    7. const assert = require('assert')
    8. let model = TestModel.loadModel(__dirname + "/model1.tmodel");
    9. //// 你的步骤定义 /////
    10. Given(/^打开Windows记事本应用$/, async function () {
    11. let notepad = model.getWindow("Notepad");
    12. if (!await notepad.exists()) {
    13. Util.launchProcess('c:\\Windows\\notepad.exe');
    14. } else {
    15. await notepad.activate();
    16. };
    17. });
    18. When(/^在记事本中输入文本"([^"]*)"$/, async function (text) {
    19. await model.getDocument("文本编辑器").set(text);
    20. });
    21. When(/^选择\[文件\] \-> \[保存\]以显示文件保存对话框$/, async function () {
    22. await model.getMenuItem("文件").click();
    23. await cuketest.delay(500);
    24. await model.getMenuItem("保存").click();
    25. });
    26. When(/^输入文件名"([^"]*)"并单击\[确定\]$/, async function (fileName) {
    27. this.fileName = __dirname + '\\' + fileName;
    28. if (fs.existsSync(this.fileName)) {
    29. fs.unlinkSync(this.fileName); //remove the file if it exists
    30. }
    31. await cuketest.delay(1000)
    32. await model.getEdit("文件名").set(this.fileName);
    33. await model.getButton("保存按钮").click();
    34. });
    35. Then(/^文件应该保存成功$/, async function () {
    36. await cuketest.delay(1000)
    37. assert.ok(fs.existsSync(this.fileName), `${this.fileName} should exists`);
    38. });
    39. When(/^选择\[格式\] \-> \[字体\.\.\.\]打开字体对话框$/, async function () {
    40. await model.getMenuItem("格式").click();
    41. await model.getMenuItem("字体").click();
    42. await cuketest.delay(1000);
    43. });
    44. When(/^从\[字体\]下拉框中选择\[Arial\]字体$/, async function () {
    45. await model.getListItem("Arial").scrollIntoView();
    46. await cuketest.delay(1000);
    47. });
    48. When(/^单击\[确定\]按钮以关闭\[字体\.\.\.\]对话框$/, async function () {
    49. await model.getButton("确定").click();
    50. });
    51. Then(/^字体应有设置为\[Arial\]$/, async function () {
    52. //截屏
    53. let screenshot = await model.getWindow("Notepad").takeScreenshot();
    54. this.attach(screenshot, 'image/png');
    55. });
    56. ```

    为了确保它在重复运行中成功运行,它将在保存之前删除现有文件。

    4. 运行

    点击项目运行按钮,既可以自动执行我们定义的操作。运行完成后会自动打开测试报告视图。

    report_html.pngreport_html.png

    我们看到,我们可以截屏,观察字体调整的状况。