pytest中的fixture执行顺序是什么?

63 投票
5 回答
47457 浏览
提问于 2025-04-19 18:33

我在测试一个应用程序时,想创建一个autouse=True的工具,这个工具会修改smtplib.SMTP.connect的行为,让测试在意外尝试发送邮件时失败。

不过,在我确实希望测试发送邮件的情况下,我想用另一个工具来记录这些邮件(很可能是通过使用pytest-localserver中的smtpserver工具,并修改connect方法,让它使用那个工具返回的主机和端口)。

当然,这样做的前提是这个自动使用的工具要在其他工具之前执行(其他工具作为函数参数加载)。请问工具的执行顺序是固定的吗?或者有没有办法确保执行顺序?

5 个回答

-1

通过下面的代码,我们可以很简单地设置一些固定数据或函数的执行顺序。

比如说:

首先执行的顺序

@pytest.mark.order(1)

其次执行的顺序

@pytest.mark.order(2)
2

如果我没记错的话,你可以依赖于更高层级的固定装置(fixtures)先执行。所以,如果你创建了一个会话级别的自动使用的固定装置,用来修改 smtplib.SMTP.connect 的行为,那么你可以再创建一个函数级别的固定装置,专门在某个测试中撤销这个修改,测试结束后再恢复它。我想最简单的方法是创建你自己的 smtpserver 固定装置,这个装置依赖于 disallow_smtp 固定装置和 pytest-localserver 中的 smtpserver 固定装置,然后处理好这两个装置之间的所有设置和清理工作。

顺便提一下,这大致就是 pytest-django 处理数据库访问的方式,你可以去看看那里的代码,但那并不是一个简单的例子,而且里面有很多自己独特的东西。

12

我之前遇到了一个问题,涉及到两个自动使用的功能范围的测试准备工具(fixture)。我希望准备工具b在准备工具a之前运行,但每次都是a先运行。我想可能是按字母顺序来决定的,于是我把a改名为c,结果b就先运行了。看起来pytest并没有对此进行详细说明,这纯属是我运气好。:-)

这是关于自动使用的准备工具。如果考虑更广泛的范围(比如modulesession),准备工具会在pytest遇到需要它的测试时执行。所以如果有两个测试,第一个测试使用了一个名为sbsession范围的准备工具,而没有使用名为sa的准备工具,那么sb就会先执行。当下一个测试运行时,如果它需要sa,那么sa就会被启动。

30

简要说明

在构建测试夹具的评估顺序时,有三个方面需要一起考虑,这些方面的优先级是有顺序的:

  • 夹具依赖关系 - 夹具的评估是从最根本的需求开始,逐步回到测试函数中需要的夹具。
  • 夹具作用域 - 夹具的评估顺序是从 session(会话)到 module(模块),再到 function(函数)作用域。在同一个作用域中,autouse(自动使用的)夹具会在非自动使用的夹具之前被评估。
  • 夹具在测试函数参数中的位置 - 夹具的评估顺序是根据它们在测试函数参数中的出现顺序,从最左边到最右边。

官方的解释和代码示例可以通过下面的链接查看

https://docs.pytest.org/en/stable/fixture.html#fixture-instantiation-order

更新

当前的文档提到的三个因素是唯一需要考虑的,同时不建议依赖其他因素(比如测试函数参数中的顺序):

  1. 作用域
  2. 依赖关系
  3. 自动使用

上面的链接是过时的。请查看 更新后的链接

58

控制测试用例执行顺序最简单的方法,就是在后面的测试用例中请求前面的测试用例。比如,如果你想确保 ba 之前执行,可以这样做:

@pytest.fixture(autouse=True, scope="function")
def b():
    pass

@pytest.fixture(scope="function")
def a(b):
    pass

想了解更多关于测试用例执行顺序的细节,可以看看 Maxim的精彩回答,或者查看 官方文档

撰写回答