(全文约2400字,阅读约需6分钟,首发于公众号:测试开发研习社,欢迎关注)
1. 为什么从 fixture 改为 hook
从难度上来说,fixture 显然更容易上手,也更被众人熟悉。
改成 hook 之后,无形提升了使用门槛,但也提供了更多灵活性
举个例子,hook 可以让多种对 excel 的的处理方案共存:
-
对于 xxx 内容,使用 allure 进行报告标注
-
对于 yyy 内容,使用 requests 进行 HTTP 请求
-
对于 xxx 内容,使用 selenium 进行浏览器自动化
-
等等...
这里的多个hook可以共存,它们自动根据 excel 内容,进行判断、选择、执行。
如果是 fixture 的话,大家都知道,而同名的 fixture 会彼此覆盖,
也就是说,就算你创建再多不同运行的 fixture,最后只有一个 fixture 可以被使用
那么,为了应对不同的测试类型和业务场景,
要把所有的代码都写在这唯一的一个 fixtures 里吗?
想想都觉得可怕...
hook 的方案让 pytest-xlsx 也支持插件,
这样一来,任何人都可以定义、分享不同的 excel 处理方式,
每一个项目可以安装不同的处理方式,从而能够同时兼容:
接口测试、
Web 测试、
调用 Python 函数、执行 SQL、
标注Allure
等处理方式
2. 如何使用 hook 自定义 excel 处理方式
这个问题等同于:“如何为 pytest-xlsx 开发插件”
可能需要稍微练习才能掌握
1. 创建 excel 文件
假设有 xlsx 表格内容如下图:
将其保存为 test_sanmu.xlsx
,然后执行 pytest
pytest test_sanmu.xlsx
执行结果如下:
具体执行过程可以通过 -vs
参数查看:
此时说明 pytest-xlsx 插件正常加载,已经可以将 xlsx 文件中的内容作为用例步骤进行执行
2. 创建 hook
pytest 加载 xlsx 文件后,会将表格中的每一行作为用例步骤,传递给 hook,
通过定义 pytest_xlsx_run_step
,来控制用例执行细节
新建文件 conftest.py
,并写入以下内容
from pytest_xlsx.file import XlsxItem
def pytest_xlsx_run_step(item: XlsxItem): # hook在执行xlsx用例内容时被调用
print(item.current_step) # 打印用例内容
return True # 跳过其他hook执行
执行结果如下
此时说明pytest执行excel的方式已经被hook改变
如果你想根据 xlsx 内容做更多的事情,比如关键字驱动测试,
那么只需要继续在 pytest_xlsx_run_step
补充代码即可
3. 处理 item
hook 的参数 item
,是 XlsxItem
的实例对象,代表了当前正在执行用的用例。
但是正如前面所言,hook 是在执行每一个步骤时被自动调用
也就是说,同一个用例在执行过程中,会将 item 作为参数,对 hook 进行多次调用
那 hook 是如何知道这一个步骤的内容是
item 拥有以下属性:
属性名 | 属性内容 | 类型 | 备注 |
---|---|---|---|
xlsx_data | 从 xlsx 中读取到的全部数据 | dict | |
nodeid | 当前测试用例 id | str | |
name | 当前用例名称 | str | |
current_step_no | 当前用例步骤序号 | int | 第一个是 0 |
current_step | 当前步骤内容 | dict | |
max_step_no | 最大用例步骤序号 | int | 步骤数量 - 1 |
is_first_step | 是否是第一个步骤 | bool | |
is_last_step | 是否最后一个步骤 | bool |
读取 current_step
属性即可得到当前测试步骤的内容
此外,通过读取 is_first_step
和 is_last_step
属性,可判断用例是否开始执行,以及是否执行结束
from pytest_xlsx.file import XlsxItem
def pytest_xlsx_run_step(item: XlsxItem):
if item.is_first_step:
print("准备执行:用例的第一个步骤,此时可以进行前置操作")
print("开始执行xlsx测试步骤", "-" * 10)
print(item.current_step)
print("xlsx测试步骤执行完毕", "-" * 10)
if item.is_last_step:
print("执行完毕:用例的最后一个步骤,此时可以进行后置操作")
return True
执行结果如下
3. 跳过其他 hook
按照 pytest 的 hook 规则,同一个 hook 可以有多个实现。
这样就会使用例的步骤,被第一个 hook 处理之后,还可以被第二个 hook 继续处理。
如果在某些场景中,不需要其他 hook 进行二次处理,可以通过返回 True
进行跳过
例如下面的代码,会让所有的 hook 被跳过,于是 excel 中的内容完全不被处理
def pytest_xlsx_run_step(item: XlsxItem):
return True
在处理用例步骤时候,是否需要返回 True
,基于一个基本原则:
该测试步骤是否已被妥善处理
举个例子:
假设有一个 excel 编写的 web 自动化测试用例,那么:
-
日志记录 hook:读取步骤内容,记录日志,返回 None,调用下一个 hook
-
api 测试 hook:不对其进行任何操作,返回 None,调用下一个 hook
-
web 测试 hook:根据步骤进行浏览器控制,返回 True,停止 hook 调用
假设有一个 excel 编写的 api 自动化测试用例,那么:
-
日志记录 hook:读取步骤内容,记录日志,返回 None,调用下一个 hook
-
api 测试 hook:根据步骤进行接口请求,返回 True,停止 hook 调用
-
web 测试 hook:已被跳过,不会执行
3. 内置的插件参考
目前,pytest-xlsx 内置了三个插件,它们都是通过 hook 的方式处理 excel 用例步骤,可以作为一个示例进行参考
1. PrintXlsxPlugin
该插件可以将用例步骤打印到控制台
2. RunnerXlsxPlugin
该插件会调用 fixture,并使用 fixtures 的返回值
3. AllureXlsxPlugin
该插件判断测试步骤是否 allure
开头,如果是的话就进行 allure 标记
4. Excel 执行 API 自动化示例
思路和步骤:
-
为用例添加标记
api_case
-
在 hook 中判断用例是否拥有该标记
-
读取用例步骤进行测试
1. 创建 excel
2. 定义 hook
5. Excel 执行 Web 自动化测示例
思路和步骤:
-
为用例添加标记
web_case
-
在 hook 中判断用例是否拥有该标记
-
读取用例步骤
-
根据步骤的包含的关键字,控制浏览器操作
内容:
略
后续开发计划
在保存或尽量减少对已有 hook 的改动的原则下,创建更多的可热插拔的插件
-
[ ] excel 用例调用 shell 命令
-
[ ] excel 用例调用 Python 函数
-
[ ] excel 用例执行 SQL 语句
欢迎关注、体验和反馈