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


为啥用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结果 , 就会将该结果作为整个钩子调用的结果 。在这种情况下 , 将不会调用其余钩子函数 。
3. hook函数中的 hookwrapper回到插件代码本身 , 也用到了一个参数hookwrapper=True
钩子 【pytest官方文档】解读-插件开发之hooks 函数

文章插图
默认情况下 , 我们之间重写hook函数来彻底改变它要做的事情 , 就像插件代码里第一个hook函数pytest_sessionstart一样 。
hookwrapper=True时 , 等于是我们实现了一个hook函数的包装器 。钩子包装器是一个生成器函数 , 它只产生一次 。
当 pytest 调用钩子时 , 首先执行钩子包装器 , 并像常规钩子一样传递相同的参数 。
yield关键字大家都熟悉了 , 当代码执行到这里的时候会暂停一下 , 继续执行下一个钩子 , 并且会把所有的结果或者异常封装成一个result对象返回到yield这里 。
钩子包装器本身并不返回结果 , 只是在实际的钩子实现的外面做一些其他的事情 。
我们的插件功能其实也并不是要修改这个钩子本身测试报告的内容 , 所以就直接通过hookwrapper=True将我们的pytest_runtest_makereport写成一个包装好的钩子 。
接下来就是具体功能的代码 , 判断当用例测试结果是fail , 就写到本地文件中 。
运行运行一下测试用例 , 看下我们插件的执行情况 。
钩子 【pytest官方文档】解读-插件开发之hooks 函数

文章插图
查看下failures.txt内容 , 结果正确 。
钩子 【pytest官方文档】解读-插件开发之hooks 函数

文章插图
四、钩子函数排序/调用示例存在这样的情况 , 对于同一个钩子规范 , 可能会存在多个实现 。这种情况下可以使用参数tryfirsttrylast来影响钩子的调用顺序 。
# Plugin 1@pytest.hookimpl(tryfirst=True)def pytest_collection_modifyitems(items):# 尽可能早的执行...# Plugin 2@pytest.hookimpl(trylast=True)def pytest_collection_modifyitems(items):# 尽可能晚的执行...# Plugin 3@pytest.hookimpl(hookwrapper=True)def pytest_collection_modifyitems(items):# 会在上面的 tryfirst 之前执行outcome = yield# 在执行所有非钩子包装器之后执行

经验总结扩展阅读