钩子 【pytest官方文档】解读-插件开发之hooks 函数

上一节讲到如何安装和使用第三方插件,用法很简单 。接下来解读下如何自己开发pytest插件 。
但是,由于一个插件包含一个或多个钩子函数开发而来 , 所以在具体开发插件之前还需要先学习hooks函数 。
一、什么是 hooks 函数简单来说,在 pytest 的代码中,预留出了一些函数供我们修改,以便来改变pytest工作方式 , 这些函数就是hooks函数,我们可以直接重写函数里的内容 。
比如,在 pytest代码路径\Lib\site-packages\_pytest\hookspec.py中,可以看到 pytest 定义好的 hook 规范,方便我们在开发插件的时候参考规范来调用对应的hooks函数 。

钩子 【pytest官方文档】解读-插件开发之hooks 函数

文章插图
二、hooks 函数的分类从hooks函数的职责分类来看,大概如下几类:
  • Bootstrapping hooks:引导类钩子,用来调用已经早就注册好的内部插件和第三方插件 。
  • Collection hooks:集合类钩子 , pytest 调用集合钩子来收集文件和目录 。
  • Test running (runtest) hooks:测试运行相关的钩子,所有与测试运行相关的钩子都接收一个pytest.Item对象 。
  • Reporting hooks:与Session 会话相关的钩子 。
  • Debugging/Interaction hooks:调试/交互钩子,少有的可以用于特殊的报告或与异常交互的钩子函数 。
可供调用的钩子函数有很多,功能也是各式各样的,有兴趣的童鞋可以进一步细看官方文档里的介绍 。我们就是要通过不同钩子函数具备的功能 , 来实现我们自定义的需求 。
三、编写 hooks 函数开发本地插件写一个插件示例 。
比如我们平时执行case的时候 , 一通跑完可能会出现不少失败的case,那通常我可能就会翻控制台的输出来找出哪些case失败了 。
但是控制台里输出的信息有很多,于是乎我想直接把测试失败的case信息存到一个本地文件里 , 我直接打开就可以看到所有失败的case 。
先写一个case文件里的建议测试用例:
# content of mytest/tests.pydef test_failed():assert Falsedef test_passed():assert Truedef test_failed2():assert False然后再同级目录下创建一个conftest文件,之前聊fixture时候就说过,conftest里的内容就是本地插件了 。
先直接放上插件代码:
# content of mytest/conftest.pyimport pytestfrom pathlib import Pathfrom _pytest.main import Sessionfrom _pytest.nodes import Itemfrom _pytest.runner import CallInfofrom _pytest.terminal import TerminalReporterFAILURES_FILE = Path() / "failures.txt"@pytest.hookimpl()def pytest_sessionstart(session: Session):print("Hello 把苹果咬哭")if FAILURES_FILE.exists():FAILURES_FILE.unlink()FAILURES_FILE.touch()@pytest.hookimpl(hookwrapper=True)def pytest_runtest_makereport(item: Item, call: CallInfo):outcome = yieldresult = outcome.get_result()if result.when == "call" and result.failed:try:with open(str(FAILURES_FILE), "a") as f:f.write(result.nodeid + "\n")except Exception as e:print("ERROR", e)pass解析
1. 重写钩子函数首先,关于pathlib模块就是用来做一些路径操作的库,因为我要在本地路径中进行文件相关操作 。
def pytest_sessionstart()中做的事情就是先看下本地是否存在这个名字叫failures.txt的文件 , 有的话就删除,没有就新建 。
为啥用pytest_sessionstart这个hook函数,因为通过查看官方API文档里的介绍 , 发现这个钩子函数是在创建Session对象之后,且在执行收集和进入运行测试循环之前调用,所以很适合用在这里 。
所以直接重写这个hook函数来实现我们定义的功能 。
2. hook函数中的 firstresult示例中使用hook函数pytest_runtest_makereport,同样通过查看官方API介绍 , 它的作用是为测试用例的每个setup运行tearDown阶段创建TestReport 。而插件要做的事情,就是要在用例执行后获取到状态,若是失败就存放到本地txt文件 。
当查看hook规范时候 , 发现一个装饰器参数firstresult=True
钩子 【pytest官方文档】解读-插件开发之hooks 函数

文章插图
由于在大多数情况下,调用hook函数可能还会触发调用多个hook,所以最后的结果会是包含所调用钩子函数的非none结果
firstresult=True时,调用钩子函数时只要有第一个返回非none结果,就会将该结果作为整个钩子调用的结果 。在这种情况下,将不会调用其余钩子函数 。

推荐阅读