首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

pytest-xlsx:使用hook自定义excel用例的执行方式

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 拥有以下属性:

读取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

该插件可以将用例步骤打印到控制台

def pytest_xlsx_run_step(self, item: XlsxItem, request: FixtureRequest): print("-" * 10) print(f"当前用例id:{item.nodeid}") print(f"当前用例名称:{item.name}") print(f"当前用例步骤:{item.current_step}") print(f"当前用例步骤序号:{item.current_step_no}") print(f"最大用例步骤序号:{item.max_step_no}") print(f"当前是否第一个步骤:{item.is_first_step}") print(f"当前是否最后一个步骤:{item.is_last_step}")

if item.is_last_step: print("=" * 20)

2. RunnerXlsxPlugin

该插件会调用 fixture,并使用 fixtures 的返回值

注意:此插件是为了兼容 pytest-xlsx 0.3.* 的写法。计划在 0.7.* 移除,之后只支持 hook 方法

def pytest_xlsx_run_step(self, item: XlsxItem, request: FixtureRequest): try: xlsx_runner = request.getfixturevalue("xlsx_runner") warnings.warn( "xlsx_runner已被弃用,请改用hook执行XlsxItem,详情咨询wx:python_sanmu", DeprecationWarning, ) except Exception: return

xlsx_runner.execute(item) return True

3. AllureXlsxPlugin

该插件判断测试步骤是否allure开头,如果是的话就进行 allure 标记

import allure

def pytest_xlsx_run_step(self, item: XlsxItem): ... mark = str(item.current_step.get(self.meta_column_name, "")) value = str(item.current_step.get(arg_column_name, ""))

if not mark.startswith("allure"): #判断是否allure开头 return None if not value: return None

label = mark.split("_")[-1]

if label == "step": with allure.step(value): #调用allure,在测试报告中进行标记 ...

4. Excel 执行 API 自动化示例

思路和步骤:

为用例添加标记api_case

在 hook 中判断用例是否拥有该标记

读取用例步骤进行测试

1. 创建 excel

2. 定义 hook

def pytest_xlsx_run_step(item: XlsxItem): if not list(item.iter_markers("api_case")): return None # 未标记未接口测试用例,不处理

step = item.current_step

# 发送请求 kwargs = { "method": step["标记"], "url": step["接口地址"], step["请求方式"]: json.loads(step["请求参数"]), }

resp = requests.request(**kwargs) # 验证结果

assert str(resp.status_code) == str(step["预期状态码"]) assert re.findall(str(step["预期响应"]), resp.text)

# 保存变量 ...

5. Excel 执行 Web 自动化测示例

思路和步骤:

为用例添加标记web_case

在 hook 中判断用例是否拥有该标记

读取用例步骤

根据步骤的包含的关键字,控制浏览器操作

内容:

后续开发计划

在保存或尽量减少对已有 hook 的改动的原则下,创建更多的可热插拔的插件

[ ] excel 用例调用 shell 命令

[ ] excel 用例调用 Python 函数

[ ] excel 用例执行 SQL 语句

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OhAWhM8Lq6hLK4HBmCGBhMpw0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券