如何在有全局夹具的情况下将Python单元测试转换为py.test?
我有一套单元测试,是用Python的unittest模块写的。它们使用了setUpModule()这个函数来加载一个全局变量,这个变量包含了运行测试所需的共享“东西”(包括一些HTTP会话)。
当我用unittest
运行我的测试时,一切正常。但用py.test
运行时,就失败了。
我稍微修改了一下,试着用旧版的pytest的fixture函数(这些函数的名字和unittest的不一样)来运行。这样做是成功了,但只有在不使用多线程的情况下才行,而我其实是想用多线程的。
文档里的例子对我来说没什么用,因为我有大约20个类(unittest.TestCase),每个类里面有10个测试。显然,我不想在每个测试里都加一个新的参数。
到目前为止,我一直使用类里的setUp()方法来加载共享的字典,然后在每个测试中使用它。
#!/usr/bin/env python
# conftest.py
@pytest.fixture(scope="session")
def manager():
return { "a": "b"}
现在是测试的部分:
#!/usr/bin/env python
# tests.py
class VersionTests(unittest.TestCase):
def setUp(self):
self.manager = manager
def test_create_version(self):
# do something with self.manager
pass
请记住,我需要一个能在多线程下工作的解决方案,而且只调用一次fixture。
1 个回答
pytest
确实可以运行 unittest
的测试,这在 支持 unittest.TestCase / 夹具集成 的文档中有说明。不过,有一点需要注意的是,直接使用 pytest
的函数参数夹具 并不推荐:
虽然 pytest 支持通过测试函数的参数接收夹具,但
unittest.TestCase
的方法不能直接接收夹具函数的参数,因为这样做可能会影响运行一般的unittest.TestCase
测试套件的能力。
假设我们有一个测试模块,像这样使用标准的 unittest
初始化功能:
# test_unittest_tests.py (for the sake of clarity!)
import unittest
manager = None
def setUpModule():
global manager
manager = {1: 2}
class UnittestTests(unittest.TestCase):
def setUp(self):
self.manager = manager
def test_1_in_manager(self):
assert 1 in self.manager
def test_a_in_manager(self):
assert 'a' in self.manager
当用 unittest
运行时,会产生以下输出:
$ python -m unittest -v test_unittest_tests
...
test_1_in_manager (test_unittest_tests.UnittestTests) ... ok
test_a_in_manager (test_unittest_tests.UnittestTests) ... FAIL
...
test_a_in_manager
按预期失败了,因为在 manager
目录中没有 'a'
这个键。
我们设置了一个 conftest.py 文件,为这些测试提供了作用域的 pytest
夹具。比如这样做,不会破坏标准的 unittest
行为,也不需要对测试进行任何修改,使用 pytest
的自动使用功能:
# conftest.py
import pytest
@pytest.fixture(scope='session', autouse=True)
def manager_session(request):
# create a session-scoped manager
request.session.manager = {'a': 'b'}
@pytest.fixture(scope='module', autouse=True)
def manager_module(request):
# set the sessions-scoped manager to the tests module at hand
request.module.manager = request.session.manager
用 pytest
运行测试(使用 pytest-xdist
进行并行化),会产生以下输出:
$ py.test -v -n2
...
[gw1] PASSED test_unittest_tests.py:17: UnittestTests.test_a_in_manager
[gw0] FAILED test_unittest_tests.py:14: UnittestTests.test_1_in_manager
...
现在 test_1_in_manager
失败了,因为在 pytest
提供的 manager 字典中没有 1
这个键。