Python 使用依赖项注入将PyTest fixture添加到测试类

Python 使用依赖项注入将PyTest fixture添加到测试类,python,dependency-injection,pytest,fixtures,Python,Dependency Injection,Pytest,Fixtures,我将Python3与PyTest一起使用,并在conftest.py中定义了许多fixture对象。我遇到的问题是,每个测试用例都需要一些fixture对象。在所有测试用例中请求这些夹具引用会导致大量重复的样板代码 这是conftest.py中的夹具: def fixtureA(请求): _fixture=FixtureA() #初始化设备,处理请求 返回装置 这是当前的测试类,我想从参数中删除所有装置以提高可读性: 类TestSomeFeature(BaseTest): def测试某些功能(

我将Python3与PyTest一起使用,并在
conftest.py
中定义了许多fixture对象。我遇到的问题是,每个测试用例都需要一些fixture对象。在所有测试用例中请求这些夹具引用会导致大量重复的样板代码

这是
conftest.py
中的夹具:

def fixtureA(请求):
_fixture=FixtureA()
#初始化设备,处理请求
返回装置
这是当前的测试类,我想从参数中删除所有装置以提高可读性:

类TestSomeFeature(BaseTest):
def测试某些功能(self、fixtureA、fixtureB、fixtureC):
fixtureA.doSomething()
#执行测试用例,处理其他设备
def测试某些其他功能(self、fixtureA、fixtureB、fixtureC):
data=fixtureB.getData()
#执行测试用例
这种方法是可行的,但我想找到一种方法,使用依赖注入(或类似方法)在
BaseTest
属性中自动注入fixture,而不必在每个测试用例的参数列表中指定它们。我正在寻找类似的东西,但我愿意接受任何其他建议:

类基本测试:
#这不起作用,因为pytest不允许在测试类中使用构造函数
定义初始值(fixtureA、fixtureB、fixtureC):
self.fixtureA=fixtureA
self.fixtureB=fixtureB
self.fixtureC=fixtureC
我希望测试类看起来像这样,更干净

类TestSomeFeature(BaseTest):
def测试某些功能(自身):
self.FixtureA.doSomething()
#执行测试用例
def测试某些其他功能(自身):
data=self.FixtureB.getData()
#执行测试用例

首先,您可以在
conftest.py
和测试类中定义装置。区别在于可见性:如果在
conftest.py
文件中定义了一个夹具,则该夹具对该
conftest.py
文件及其以下级别的所有测试都可见。如果您在测试模块中定义了它,则它仅在此模块中可见。如果您在测试类中定义它,则它在该类和派生类中可见

还请注意,如果您返回一个值,也可以使用
autotest=True
,您只需在相应的测试中引用夹具即可。也可以将装置值保存在变量中。如果您使用的是基类,以下是两种情况的简化示例:

类测试库:
@pytest.fixture(autouse=True)
def固定器1(自):
self.value1=1#保存夹具值
产量
@pytest.fixture
def固定器2(自身):
收益率2#返回夹具值-必须引用fixtue
#如果存在设置/拆卸代码,自动使用仍然有意义,
#且夹具不得在所有试验中引用
@pytest.fixture(autouse=True)
def固定装置3(自身):
self.value3=3
收益率3#两个都做-可以任意使用
类TestDerived(TestBase):
def测试_1(自身):
断言self.value1==1
def测试_2(自身,固定装置2):
断言fixture2==2
def测试_3_1(自身):
断言self.value3==3
def测试_3_2(自身、固定装置3):
断言fixture3==3

请注意,如果您引用该设备,您将获得设备值,而不是设备本身,因此无需(而且不可能)调用该设备-而是直接使用该设备返回的值。

以下代码基于@MrBeanBremen的答案

您可以在名为
injector
的基类中创建一个fixture,其唯一职责是将fixture从
conftest
注入基类:

类基本测试:
@夹具(自动使用=真)
#无检查PyAttributeOutsideInit
def喷射器(自、固定器A、固定器B):
self.fixtureA=fixtureA
self.fixtureB=fixtureB

继承自
BaseTest
的所有测试类现在都可以访问fixture,而无需任何样板代码。构造函数不能在
BaseTest
中使用,因为如果实现了构造函数,PyTest将完全忽略测试类。PyCharm将生成一个弱警告,因为我们在
\uuuu init\uuuuuu
之外分配属性,但是可以使用
noinspection
注释来抑制该警告。

如果您需要所有测试,只需使用
autotest=True
。如果在测试类(或基类)的所有测试中都需要它,请将其放入该类中,并设置
autouse=True
。也许我不明白它的用法…@Beanbremen先生谢谢你的反馈。如果有什么不清楚的地方,我会尽量澄清,然后你可以投票表决,如果它是完整和明确的问题。我添加了一个编辑,解释了为什么我不认为可以使用autouse,并在开头添加了一个代码片段,显示装置如何返回对对象的引用,不仅仅是执行一块代码。@beanbreman先生,我也不清楚您的建议:您是说我应该将fixture代码从
conftest.py
移动到基类吗?你能在PyTest中做到吗?我认为fixture必须在
conftest
中。我把它放在了答案中,我希望这能澄清一点。(旁白:我们尽量不在这里的问题中添加答案材料。但是,欢迎您自行回答,因此,如果您想提供基于提供的答案的最终解决方案,制作一篇回答文章比编辑问题更可取。我已将此发布为社区维基;如果您想自己发布,请这样做,并让我知道,因此我将删除CW副本)。效果很好。谢谢你的提示。IDE抱怨没有在init中分配属性,但我可以接受。