演练:创建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

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