使用依赖注入将 PyTest fixture 添加到测试 class
Add PyTest fixtures to a test class using dependency injection
我将 Python 3 与 PyTest 一起使用,并在 conftest.py
中定义了许多固定对象。我遇到的问题是每个测试用例都需要一些固定对象。在所有测试用例中请求这些夹具引用会导致大量重复的样板代码。
这是 conftest.py
中的固定装置:
def fixtureA(request):
_fixture = FixtureA()
# initialize the fixture, do stuff with request
return _fixture
这是当前测试 class,为了便于阅读,我想从参数中删除所有固定装置:
class TestSomeFeature(BaseTest):
def test_some_function(self, fixtureA, fixtureB, fixtureC):
fixtureA.doSomething()
# execute test case, do stuff with other fixtures
def test_some_other_function(self, fixtureA, fixtureB, fixtureC):
data = fixtureB.getData()
# execute test case
这种方法有效,但我想找到一种方法来使用依赖注入(或类似方法)自动将固定装置注入 BaseTest
属性中,而不必在每个测试用例的参数列表中指定它们。我正在寻找类似的东西,但愿意接受任何其他建议:
class BaseTest:
# This does not work, since pytest does not allow constructors in the test class
def __init__(fixtureA, fixtureB, fixtureC):
self.fixtureA = fixtureA
self.fixtureB = fixtureB
self.fixtureC = fixtureC
我希望测试 class 看起来像这样,干净多了!
class TestSomeFeature(BaseTest):
def test_some_function(self):
self.FixtureA.doSomething()
# execute test case
def test_some_other_function(self):
data = self.FixtureB.getData()
# execute test case
首先,您可以在 conftest.py
和测试 class 中定义固定装置。不同之处在于可见性:如果您在 conftest.py
中定义夹具,则该 conftest.py
文件级别及以下级别的所有测试都可以看到它。如果您在测试模块中定义它,则它仅在该模块中可见。如果您在测试 class 中定义它,它在此 class 中可见并派生 classes.
另请注意,如果您 return 一个值,您也可以使用 autotest=True
- 您只需要在相应的测试中引用夹具。您还可以将夹具值保存在变量中。如果您使用的是基数 class:
,则这是两种情况的简单示例
class TestBase:
@pytest.fixture(autouse=True)
def fixture1(self):
self.value1 = 1 # save the fixture value
yield
@pytest.fixture
def fixture2(self):
yield 2 # return the fixture value - fixtue has to be referenced
# autouse can still make sense if there is setup/tearDown code,
# and the fixture must not be referenced in all of the tests
@pytest.fixture(autouse=True)
def fixture3(self):
self.value3 = 3
yield 3 # do both - can be used either way
class TestDerived(TestBase):
def test_1(self):
assert self.value1 == 1
def test_2(self, fixture2):
assert fixture2 == 2
def test_3_1(self):
assert self.value3 == 3
def test_3_2(self, fixture3):
assert fixture3 == 3
注意你得到的是夹具值,而不是夹具本身,如果你引用夹具,所以没有必要(也不可能)调用 fixture - 而不是直接使用由 fixture 编辑的值 return。
以下代码基于@MrBeanBremen 的回答。
您可以在基础 class 中创建一个名为 injector
的夹具,其唯一职责是将 conftest
中的夹具注入基础 class:
class BaseTest:
@fixture(autouse=True)
# noinspection PyAttributeOutsideInit
def injector(self, fixtureA, fixtureB):
self.fixtureA = fixtureA
self.fixtureB = fixtureB
所有继承自 BaseTest
的测试 classes 现在无需任何样板代码即可访问固定装置。 BaseTest
中不能使用构造函数,因为如果实现了构造函数,PyTest 将完全忽略测试 class。 PyCharm 将生成弱警告,因为我们在 __init__
之外定义属性,但可以使用 noinspection
注释来抑制。
我将 Python 3 与 PyTest 一起使用,并在 conftest.py
中定义了许多固定对象。我遇到的问题是每个测试用例都需要一些固定对象。在所有测试用例中请求这些夹具引用会导致大量重复的样板代码。
这是 conftest.py
中的固定装置:
def fixtureA(request):
_fixture = FixtureA()
# initialize the fixture, do stuff with request
return _fixture
这是当前测试 class,为了便于阅读,我想从参数中删除所有固定装置:
class TestSomeFeature(BaseTest):
def test_some_function(self, fixtureA, fixtureB, fixtureC):
fixtureA.doSomething()
# execute test case, do stuff with other fixtures
def test_some_other_function(self, fixtureA, fixtureB, fixtureC):
data = fixtureB.getData()
# execute test case
这种方法有效,但我想找到一种方法来使用依赖注入(或类似方法)自动将固定装置注入 BaseTest
属性中,而不必在每个测试用例的参数列表中指定它们。我正在寻找类似的东西,但愿意接受任何其他建议:
class BaseTest:
# This does not work, since pytest does not allow constructors in the test class
def __init__(fixtureA, fixtureB, fixtureC):
self.fixtureA = fixtureA
self.fixtureB = fixtureB
self.fixtureC = fixtureC
我希望测试 class 看起来像这样,干净多了!
class TestSomeFeature(BaseTest):
def test_some_function(self):
self.FixtureA.doSomething()
# execute test case
def test_some_other_function(self):
data = self.FixtureB.getData()
# execute test case
首先,您可以在 conftest.py
和测试 class 中定义固定装置。不同之处在于可见性:如果您在 conftest.py
中定义夹具,则该 conftest.py
文件级别及以下级别的所有测试都可以看到它。如果您在测试模块中定义它,则它仅在该模块中可见。如果您在测试 class 中定义它,它在此 class 中可见并派生 classes.
另请注意,如果您 return 一个值,您也可以使用 autotest=True
- 您只需要在相应的测试中引用夹具。您还可以将夹具值保存在变量中。如果您使用的是基数 class:
class TestBase:
@pytest.fixture(autouse=True)
def fixture1(self):
self.value1 = 1 # save the fixture value
yield
@pytest.fixture
def fixture2(self):
yield 2 # return the fixture value - fixtue has to be referenced
# autouse can still make sense if there is setup/tearDown code,
# and the fixture must not be referenced in all of the tests
@pytest.fixture(autouse=True)
def fixture3(self):
self.value3 = 3
yield 3 # do both - can be used either way
class TestDerived(TestBase):
def test_1(self):
assert self.value1 == 1
def test_2(self, fixture2):
assert fixture2 == 2
def test_3_1(self):
assert self.value3 == 3
def test_3_2(self, fixture3):
assert fixture3 == 3
注意你得到的是夹具值,而不是夹具本身,如果你引用夹具,所以没有必要(也不可能)调用 fixture - 而不是直接使用由 fixture 编辑的值 return。
以下代码基于@MrBeanBremen 的回答。
您可以在基础 class 中创建一个名为 injector
的夹具,其唯一职责是将 conftest
中的夹具注入基础 class:
class BaseTest:
@fixture(autouse=True)
# noinspection PyAttributeOutsideInit
def injector(self, fixtureA, fixtureB):
self.fixtureA = fixtureA
self.fixtureB = fixtureB
所有继承自 BaseTest
的测试 classes 现在无需任何样板代码即可访问固定装置。 BaseTest
中不能使用构造函数,因为如果实现了构造函数,PyTest 将完全忽略测试 class。 PyCharm 将生成弱警告,因为我们在 __init__
之外定义属性,但可以使用 noinspection
注释来抑制。