如何为所有测试调用一次setup并在完成后调用teardown

41 投票
4 回答
38940 浏览
提问于 2025-04-17 04:26

我有一堆用pytest写的测试,这些测试都放在一个叫dir的文件夹里。比如说:

dir/test_base.py
dir/test_something.py
dir/test_something2.py
...

里面代码的简化版本如下:

test_base.py

import pytest

class TestBase:
   def setup_module(module):
      assert False

   def teardown_module(module):
      assert False

test_something.py

import pytest
from test_base import TestBase

class TestSomething(TestBase):
   def test_dummy():
       pass

test_something2.py

import pytest
from test_base import TestBase

class TestSomethingElse(TestBase):
   def test_dummy2():
       pass

我所有的test_something*.py文件都继承了test_base.py里的一个基类。现在我在test_base.py里写了setup_module(module)teardown_module(module)这两个方法。我本来希望setup_module能在所有测试开始前只调用一次,而teardown_module()能在所有测试结束后调用一次。

但是这些函数好像没有被调用?我需要加什么装饰器才能让它们工作吗?

4 个回答

1

setup_module和teardown_module是用来处理模块的,它们会在定义最终测试的模块中被调用。这也让你可以自定义设置。如果你只需要一个setup_module,可以把它放在test_base.py文件里,然后在其他地方导入使用。希望这对你有帮助。

15

setup_moduleteardown_module 放在模块的最外面,不要放在类里面。然后再添加你的测试类。

def setup_module(module):
    """..."""

def teardown_module(module):
    """..."""

class TestSomething:

    def test_dummy(self):
        """do some tests"""

想了解更多信息,可以参考 这篇文章

25

提问者的需求是希望每个测试的准备和清理工作只执行一次,而不是每个模块都执行一次。这可以通过结合使用一个名为 conftest.py 的文件、@pytest.fixture(scope="session") 装饰器,以及将这个准备工作名称传递给每个测试函数来实现。

这些内容在 Pytest的文档 中有详细说明。

下面是一个示例:

conftest.py

import pytest

@pytest.fixture(scope="session")
    def my_setup(request):
        print '\nDoing setup'
        def fin():
            print ("\nDoing teardown")
        request.addfinalizer(fin)

test_something.py

def test_dummy(my_setup):
    print '\ntest_dummy'

test_something2.py

def test_dummy2(my_setup):
    print '\ntest_dummy2'

def test_dummy3(my_setup):
    print '\ntest_dummy3'

当你运行命令 py.test -s 时,输出结果如下:

collected 3 items 

test_something.py 
Doing setup

test_dummy
.
test_something2.py 
test_dummy2
.
test_dummy3
.
Doing teardown

文件名 conftest.py 是很重要的:你不能把这个文件改成其他名字,然后期待 Pytest 能找到它作为准备工作的来源。

设置 scope="session" 是关键。否则,准备和清理工作会在每个测试模块中重复执行。

如果你不想在每个测试函数中都传递准备工作名称 my_setup,你可以把测试函数放在一个类里面,并对这个类使用 pytest.mark.usefixtures 装饰器。

撰写回答