为什么unittest.TestCase无法识别我的py.test固定装置?

30 投票
3 回答
25037 浏览
提问于 2025-04-18 00:05

我正在尝试在我的单元测试中使用 py.testfixtures,并且是和 unittest 一起使用的。我把几个 fixtures 放在项目顶层的一个 conftest.py 文件里(具体做法可以参考 这里),用 @pytest.fixture 装饰它们,并把它们的名字作为需要的测试函数的参数。

这些 fixtures 注册得很正确,像通过 py.test --fixtures test_stuff.py 命令可以看到,但当我运行 py.test 时,却出现了 NameError: global name 'my_fixture' is not defined 的错误。这个问题似乎只在我使用 unittest.TestCase 的子类时出现——不过 py.test 的文档似乎说它和 unittest 是兼容的。

为什么在我使用 unittest.TestCase 时,测试看不到这些 fixtures 呢?


不工作:

conftest.py

@pytest.fixture
def my_fixture():
    return 'This is some fixture data'

test_stuff.py

import unittest
import pytest

class TestWithFixtures(unittest.TestCase):

    def test_with_a_fixture(self, my_fixture):
         print(my_fixture)

工作:

conftest.py

@pytest.fixture()
def my_fixture():
    return 'This is some fixture data'

test_stuff.py

import pytest

class TestWithFixtures:

    def test_with_a_fixture(self, my_fixture):
         print(my_fixture)

我问这个问题更多是出于好奇;目前我只是完全放弃了 unittest

3 个回答

5
  1. 把这个“固定装置”定义成一个可以访问的变量,就像下面例子中的 input 一样。定义的方法是用 request.cls.VARIABLE_NAME_YOU_DEFINE = RETURN_VALUE

  2. 在单元测试类外部,使用 @pytest.mark.usefixtures("YOUR_FIXTURE") 来使用这个“固定装置”;在单元测试类内部,可以通过 self.VARIABLE_NAME_YOU_DEFINE 来访问这个“固定装置”。

例如:

import unittest
import pytest


@pytest.fixture(scope="class")
def test_input(request):
    request.cls.input = {"key": "value"}


@pytest.mark.usefixtures("test_input")
class MyTestCase(unittest.TestCase):

    def test_something(self):
        self.assertEqual(self.input["key"], "value")
12

你可以在 unittest.TestCase 中使用 pytest 的一些工具,叫做 fixtures,并且可以通过 pytest 的选项 autouse 来自动使用它们。不过,如果你在使用这些工具的单元测试方法中用上了 test_ 前缀,就会出现以下错误:

Fixtures are not meant to be called directly,...

### conftest.py
@pytest.fixture
def my_fixture():
    return 'This is some fixture data'

一个解决办法是使用一个叫 prepare_fixture 的方法,把这些工具设置为 TestWithFixtures 类的属性,这样所有的单元测试方法都能使用这些工具。

### test_stuff.py
       
import unittest
import pytest
    
class TestWithFixtures(unittest.TestCase):
    

    @pytest.fixture(autouse=True)
    def prepare_fixture(self, my_fixture):
        self.myfixture = my_fixture

    def test_with_a_fixture(self):
        print(self.myfixture)
24

虽然pytest支持通过测试函数的参数来接收一些准备好的数据(叫做fixtures),但对于unittest的测试方法来说,它们不能直接接收这些准备好的数据。这是因为这样做可能会影响到运行普通的unittest测试套件的能力。

更多信息可以参考下面的链接: https://pytest.org/en/latest/unittest.html

其实也可以在unittest.TestCase中使用这些准备好的数据。想了解更多,可以查看那个页面。

撰写回答