pytest中的fixture执行顺序是什么?
我在测试一个应用程序时,想创建一个autouse=True
的工具,这个工具会修改smtplib.SMTP.connect
的行为,让测试在意外尝试发送邮件时失败。
不过,在我确实希望测试发送邮件的情况下,我想用另一个工具来记录这些邮件(很可能是通过使用pytest-localserver
中的smtpserver
工具,并修改connect
方法,让它使用那个工具返回的主机和端口)。
当然,这样做的前提是这个自动使用的工具要在其他工具之前执行(其他工具作为函数参数加载)。请问工具的执行顺序是固定的吗?或者有没有办法确保执行顺序?
5 个回答
通过下面的代码,我们可以很简单地设置一些固定数据或函数的执行顺序。
比如说:
首先执行的顺序
@pytest.mark.order(1)
其次执行的顺序
@pytest.mark.order(2)
如果我没记错的话,你可以依赖于更高层级的固定装置(fixtures)先执行。所以,如果你创建了一个会话级别的自动使用的固定装置,用来修改 smtplib.SMTP.connect
的行为,那么你可以再创建一个函数级别的固定装置,专门在某个测试中撤销这个修改,测试结束后再恢复它。我想最简单的方法是创建你自己的 smtpserver
固定装置,这个装置依赖于 disallow_smtp
固定装置和 pytest-localserver
中的 smtpserver
固定装置,然后处理好这两个装置之间的所有设置和清理工作。
顺便提一下,这大致就是 pytest-django
处理数据库访问的方式,你可以去看看那里的代码,但那并不是一个简单的例子,而且里面有很多自己独特的东西。
我之前遇到了一个问题,涉及到两个自动使用的功能范围的测试准备工具(fixture)。我希望准备工具b在准备工具a之前运行,但每次都是a先运行。我想可能是按字母顺序来决定的,于是我把a改名为c,结果b就先运行了。看起来pytest并没有对此进行详细说明,这纯属是我运气好。:-)
这是关于自动使用的准备工具。如果考虑更广泛的范围(比如module或session),准备工具会在pytest遇到需要它的测试时执行。所以如果有两个测试,第一个测试使用了一个名为sb的session范围的准备工具,而没有使用名为sa的准备工具,那么sb就会先执行。当下一个测试运行时,如果它需要sa,那么sa就会被启动。
简要说明
在构建测试夹具的评估顺序时,有三个方面需要一起考虑,这些方面的优先级是有顺序的:
- 夹具依赖关系 - 夹具的评估是从最根本的需求开始,逐步回到测试函数中需要的夹具。
- 夹具作用域 - 夹具的评估顺序是从
session
(会话)到module
(模块),再到function
(函数)作用域。在同一个作用域中,autouse
(自动使用的)夹具会在非自动使用的夹具之前被评估。 - 夹具在测试函数参数中的位置 - 夹具的评估顺序是根据它们在测试函数参数中的出现顺序,从最左边到最右边。
官方的解释和代码示例可以通过下面的链接查看
https://docs.pytest.org/en/stable/fixture.html#fixture-instantiation-order
更新
当前的文档提到的三个因素是唯一需要考虑的,同时不建议依赖其他因素(比如测试函数参数中的顺序):
- 作用域
- 依赖关系
- 自动使用
上面的链接是过时的。请查看 更新后的链接
控制测试用例执行顺序最简单的方法,就是在后面的测试用例中请求前面的测试用例。比如,如果你想确保 b
在 a
之前执行,可以这样做:
@pytest.fixture(autouse=True, scope="function")
def b():
pass
@pytest.fixture(scope="function")
def a(b):
pass
想了解更多关于测试用例执行顺序的细节,可以看看 Maxim的精彩回答,或者查看 官方文档。