演练:创建Windows自动化测试
本教程旨在指导您如何结合Python和pytest-bdd框架,为Windows操作系统中的记事本(Notepad)应用编写自动化测试脚本。作为初学者进入桌面自动化领域的理想案例,记事本应用的自动化将介绍您如何利用CukeTest的录制功能,高效编写自动化测试项目。
录制生成脚本
1. 项目创建
启动CukeTest,依次点击“文件”菜单下的“新建项目”。
在弹出的对话框中,输入“NotepadTesting”作为项目名称,选择Python作为编程语言,并选中“Windows”作为项目模板。接着,设定项目存放路径。完成后,点击“创建”按钮,即可成功创建项目。
2. 开始录制脚本
在CukeTest主界面,点击“录制设置”按钮。在弹出的设置窗口中,输入待测试应用的路径。如果不预先输入路径,您可以在录制开始后使用工具栏中的“启动应用”功能来运行应用程序。对于Windows内置的记事本应用,您只需填写notepad
即可启动并开始脚本录制。
这里我们使用Windows自带的样例应用notepad
,录制一个操作记事本对话框的场景:
- 在记事本中输入文本"hello world"
- 选择【格式】->【字体】
- 从【字体】下拉框中选择"Arial"
- 从【字形】下拉框中选择"粗体"
- 从【大小】下拉框中选择"五号"
- 同时单击【确定】按钮以关闭【字体...】对话框
- 点击【文件】--【保存】
- 在文件对话框中保存为项目路径中的"helloworld.txt"
录制时的界面如下:
添加检查点
在自动化测试中,检查点(Checkpoint)是验证应用状态是否符合预期的关键部分。在CukeTest中,您可以在录制过程中快捷添加检查点。具体操作步骤如下:
快速打开检查点对话框:在录制时,通过按住Alt键并右击目标控件,您可以快速打开检查点对话框。这个功能让你能够在进行操作的同时,即时地添加验证步骤,提高测试脚本的编写效率。
添加属性检查点:对于本测试用例,我们将添加一个属性检查点来验证文本编辑器中的文本。在“属性检查点”列表中,选择“Text.text”属性(其值应为“hello world”),这就是我们要验证的目标属性。
添加图像检查点,只需切换到图像检查点标签页,并勾选需要检查的图片。这种检查点用于验证应用界面上特定图像的出现,非常适合那些以视觉元素为核心的测试场景。这里验证字体设置有没有更改成功。
确认和插入检查点脚本:选择需要验证的属性后,点击确认按钮。相应的检查点脚本就会被插入到我们的录制脚本中。
接着可以继续操作被测应用,因为录制已经开始了的缘故,所有操作都会同步的生成自动化脚本,可以在编辑器中看到。当所有操作完成后,点击工具栏中的 “停止” 按钮,就录好了一个自动化脚本。录制生成的脚本内容如下:
import os
from leanproAuto import RunSettings, WinAuto, Util
def recording():
RunSettings.set({"slowMo": 1000, "reportSteps": True})
modelWin = WinAuto.loadModel(os.path.dirname(os.path.realpath(__file__)) + "/recording.tmodel")
#启动应用 "notepad"
Util.launchProcess("notepad")
#设置控件值为 "hello world"
modelWin.getDocument("文本编辑器").set("hello world")
#点击 "格式(O)"
modelWin.getMenuItem("格式(O)").click(10, 9)
#点击 "字体(F)..."
modelWin.getMenuItem("字体(F)...").click(38, 7)
#选择列表项 "Arial"
modelWin.getList("字体(F):1").select("Arial")
#选择列表项 "粗体"
modelWin.getList("字形(Y):1").select("粗体")
#选择列表项 "20"
modelWin.getList("大小(S):1").select("20")
#点击 "确定"
modelWin.getButton("确定").click()
#检查属性
modelWin.getDocument("文本编辑器").checkProperty("Text.text", "hello world")
#检查截屏图片
modelWin.getVirtual("文本编辑器_image").checkImage()
#点击 "文件(F)"
modelWin.getMenuItem("文件(F)").click(23, 11)
#点击 "保存(S)"
modelWin.getMenuItem("保存(S)").click(74, 7)
#设置控件值为 "helloworld.txt"
modelWin.getEdit("文件名:1").set("helloworld.txt")
#点击 "关闭"
modelWin.getButton("关闭").click()
if __name__ == "__main__":
recording()
3. 运行录制好的脚本
点击 工具栏【只显示脚本列】切换CukeTest视图为只显示脚本栏,点击【运行脚本】:
整合自动化测试用例与代码
上面的操作仅仅只是将自动化操作部分录制下来了,也就是只能回放操作步骤,还不能算是测试,因为测试脚本中除了测试操作以外还需要有断言部分,即对测试操作的结果进行验证。
接下来,我们将展示如何将录制的操作脚本转化为完整的自动化测试用例。
1. 创建应用模型
录制生成的代码运行需要依赖录制时使用的模型文件,所以在整合代码之前需要先创建本次测试需要的模型文件。这里可以直接使用录制生成的模型,将它拷贝到models
目录下,并重命名为model1.tmodel
。
如果您的项目中已经包含模型文件,您可以同时打开新录制的模型文件和现有的模型文件,通过拖拽新录制的模型根节点到现有模型树中,实现模型的整合。之后,右击新添加的节点,选择“合并到兄弟节点”以完成合并。通过这种方法,新录制的控件对象就可以在现有模型中使用。
另外,您还可以在录制阶段选择“录制到现有模型”,这样新的控件对象将直接添加到现有模型中,简化了模型整合步骤。
2. 编写用例场景
打开目录中的.feature
文件,用自然语言编写与刚刚的测试对应的业务场景。这是使测试变得更加易读、更加便于管理的重要的一步,这里我们将录制的所有操作设置成两个场景,分别是“编辑内容并保存”和“更改记事本字体”:
接下来可以切换剧本的编辑模式到 文本 模式,将以下内容复制进去,再切换回 可视 模式:
有关如何使用“Visual”视图编辑要素文件的更多信息,可以参考演练:编辑Feature文件
对应的【文本】视图内容为:
# language: zh-CN
功能: 自动化记事本应用
以记事本为例,讲解在自动化测试Windows桌面应用的时候,如何解决菜单下拉问题。
比如: 记事本的【格式】--【字体】,【文件】--【保存】
场景: 编辑内容并保存
当在记事本中输入文本"hello world"
并且点击【文件】--【保存】
同时在文件对话框中保存为项目路径中的"helloworld.txt"
那么文件应该保存成功
场景: 更改记事本字体
当点击【格式】--【字体】
并且从【字体】下拉框中选择"Arial"
并且从【字形】下拉框中选择"粗体"
并且从【大小】下拉框中选择"五号"
同时单击【确定】按钮以关闭【字体...】对话框
那么字体应该设置成功
3. 修改conftest.py
conftest.py
是一个专门存放fixture的配置文件,pytest会自动识别和加载它。在CukeTest中,我们将被测应用的启动、关闭,测试环境的初始化等操作放在这个文件中。
打开根目录下的conftest.py
,修改其中的应用启动路径app_path
和模型文件路径。修改完成后,conftest.py
内容如下:
# conftest.py
from leanproAuto import Util
import os
import shutil
app_path = "notepad"
# 设置保存文件的测试缓存路径
projectPath = os.getcwd() + '\\testcache\\'
context = {}
# 等效于 BeforeAll Hook,在第一个测试开始前被调用
def pytest_sessionstart(session):
context["pid"] = Util.launchProcess(app_path)
# 清理缓存文件夹
if os.path.exists(projectPath):
shutil.rmtree(projectPath)
os.mkdir(projectPath)
# 等效于 AfterAll Hook,在所有测试结束后被调用
def pytest_sessionfinish(session):
Util.stopProcess(context["pid"])
这段代码主要完成以下几个任务:
- 应用路径:定义了被测试Windows应用的路径。
- 缓存路径:定义了缓存文件夹路径。
- 模型加载:加载了之前提到的模型文件,这对于界面自动化测试非常重要。
- 测试会话开始前:启动了被测试Windows应用并清理缓存文件夹。
- 测试会话结束后:关闭被测应用。
通过以上配置,我们的测试环境将为执行自动化测试脚本做好充分准备。
4. 编写步骤代码
现在,打开位于step_defs
目录下的test_feature1.py
文件来开始编写步骤定义代码。
pytest-bdd通过使用装饰器,将特定的Python函数与Gherkin语法编写的.feature文件中的步骤文本关联起来。例如:
from pytest_bdd import scenarios, given, when, then, parsers
# 使用parsers.parse来使步骤文本参数化,这里将接收一个"text"参数
@when(parsers.parse('我在记事本中输入文本"{text}"'), target_fixture="texts")
def enter_text(text):
# 输入文本的逻辑处理
...
# 对于没有参数的步骤文本,可以直接使用字符串
@when('我点击【文件】--【保存】')
def click_save():
# 点击保存的逻辑处理
...
这里,parsers.parse
允许我们将步骤文本中的变量例如 {text}
传递到步骤函数中作为参数。target_fixture
是一个pytest-bdd的特性,它使得步骤函数的返回值可以被之后的步骤作为输入参数使用。
接着,按照Feature文件中定义的步骤顺序,将录制得到的代码片段逐一复制到test_feature1.py
文件的相应步骤定义中,并根据实际测试需求进行调整和优化。
完成这一步骤后,您的test_feature1.py
文件将包含所有的步骤函数,它们将直接映射到Feature文件中定义的各个步骤。
为了进一步增强测试脚本,您可以使用Python的
assert
关键字添加验证点,以确认测试的预期结果。这是Python的内置断言机制,用于确认某个条件为真。您也可以利用checkProperty()方法更简便地验证GUI元素的属性。详细的检查点使用方法,请参考理解和使用检查点。
以下是更新后的test_feature1.py
示例,展示了完整的步骤定义及其实现:
# test_feature1.py
from leanproAuto import WinAuto, Util
from pytest_bdd import scenarios, given, when, then, parsers
import pytest
import os
model = WinAuto.loadModel("models/model1.tmodel")
scenarios("../features")
# 定义缓存目录
projectPath = os.getcwd() + '\\testcache\\'
# target_fixture用来将text值传递给上下文
@when(parsers.parse('在记事本中输入文本{text}'), target_fixture="texts")
def enter_text(text):
model.getDocument("文本编辑器").set(text)
# 校验文本是否设置成功
model.getDocument("文本编辑器").checkProperty("value", text)
return text
@when('点击【文件】--【保存】')
def click_save():
model.getMenuItem("文件(F)").click()
model.getMenuItem("保存(S)").invoke()
@when(parsers.parse('在文件对话框中保存为项目路径中的{filename}'), target_fixture="filepaths")
def enter_filename(filename):
# 保存到缓存路径
filepath = projectPath + filename
model.getEdit("文件名:1").set(filepath)
model.getButton("保存(S)1").click()
Util.delay(2000)
return filepath
@then('文件应该保存成功')
def saved_successfully(texts, filepaths):
Util.delay(2000)
filepath = filepaths
exist = os.path.exists(filepath)
# 添加断言
assert exist == True
print(filepath + "文件已创建")
# 更改记事本字体
@when('点击【格式】--【字体】')
def click_font():
model.getMenuItem("格式(O)").click()
model.getMenuItem("字体(F)...").invoke()
@when(parsers.parse('从【字体】下拉框中选择{font}'))
def select_font(font):
model.getComboBox("字体(F):").select(font)
Util.delay(500)
@when(parsers.parse('从【字形】下拉框中选择{weight}'))
def select_weight(weight):
model.getComboBox("字形(Y):").select(weight)
Util.delay(500)
@when(parsers.parse('从【大小】下拉框中选择{size}'))
def select_size(size):
model.getComboBox("大小(S):").select(size)
Util.delay(500)
@when('单击【确定】按钮以关闭【字体...】对话框')
def close_dialog():
model.getButton("确定").click()
Util.delay(500)
@then('字体应该设置成功')
def font_set_successfully(request):
#检查截屏图片
model.getVirtual("文本编辑器_image").checkImage()
请确保步骤函数能够准确地映射到您的.feature文件中的对应步骤。在测试执行期间,pytest-bdd将根据步骤文本自动调用它们。
执行
点击【运行项目】,可以看到自动化执行完成后生成对应的测试报告。