在pytest中使用conftest进行设置/清理

11 投票
2 回答
10326 浏览
提问于 2025-04-18 00:59

我有不同的测试文件夹(包)。我想为特定的包(文件夹)设置一些数据,并在测试结束后清理这些数据。

问题是,set_up() 在运行该文件夹的测试用例之前执行,但在运行完所有测试用例后,tear_down 并没有执行。它是在运行完其他包(文件夹)的所有测试用例后才执行的(也就是在整个pytest会话结束后)。

     [conftest.py]

     @pytest.fixture(scope="session", autouse=True)
         def set_up(request):
            '''Test package setup'''

         def tear_down():
            '''Test package teardown'''

每个文件夹里都有一个 __init__.py 文件,这个是显而易见的。

那么我该如何在运行完该文件夹的所有测试用例后,立即执行 tear_down() 呢?因为我知道:scope="module" 在这种情况下是没用的,因为我并不想为每个测试都设置和清理。

任何帮助都非常感谢。

谢谢。

2 个回答

6

conftest.py 文件是用来配置整个目录(可以理解为“包”)的。如果你在测试的根目录放一个这样的文件,它里面的会话范围的“夹具”(也就是一些准备工作)会在这个范围开始时运行,而对应的 tear_down(清理工作)会等到这个范围结束后再执行,也就是等整个测试会话结束后再做清理。如果你需要创建只在子目录(子包)中使用的夹具,就需要在那些子目录里再放一个 conftest.py 文件,并在里面定义自己的 scope='session' 的夹具。一个常见的例子是向数据库添加数据。想象一下,你想在对应的测试包中为所有测试填充你的 purchases 数据库表格,你就可以把执行这个任务的夹具放在 tests.purchases.conftest.py 文件里。

shopping_app/
tests/
    __init__.py
    conftest.py # applies to all tests
    buyers/
    products/
    purchases/
        conftest.py # only applies to this scope and sub-scopes
        __init__.py
        test1.py
        test2.py
        payments/
        refunds/
    sellers/
    stores/

tests.purchases.conftest.py 文件里,你会有普通的夹具声明。比如,一个用于预填充和删除数据库表格行的 set_up/tear_down 组合,可能看起来像这样:

@pytest.fixture(scope='session', autouse=True)
def prep_purchases(db, data):
    # set_up: fill table at beginning of scope
    populate_purchase_table_with_data(db, data)

    # yield, to let all tests within the scope run
    yield 

    # tear_down: then clear table at the end of the scope
    empty_purchase_table(db)

有些夹具不需要明确地注入到测试中(我们只关心它们的副作用,而不是它们的返回值),这就是 autouse 参数的作用。至于使用 yield 的 set_up/tear_down 的上下文管理器语法,如果你对这个不太熟悉,也可以把 tear_down 部分单独写成一个函数。

10

pytest 并不直接支持包级别的固定装置(fixtures)。unittest 也是如此。

在主要的测试框架中,我认为 nose 是唯一支持包级固定装置的框架。不过,nose2 正在取消对包级固定装置的支持。具体可以查看 nose2 的文档

pytest 支持 模块、函数、类和方法级别的固定装置,这些都是 xunit 风格的固定装置。

撰写回答