我有一个现有的pytest
测试,该测试使用一些预定义的列表来测试所有这些列表的叉积:
A_ITEMS = [1, 2, 3]
B_ITEMS = [4, 5, 6]
C_ITEMS = [7, 8, 9]
我还有一个昂贵的灯具,其内部条件取决于A和B项(而不是C),称为F:
class Expensive:
def __init__(self):
# expensive set up
time.sleep(10)
def check(self, a, b, c):
return True # keep it simple, but in reality this depends on a, b and c
@pytest.fixture
def F():
return Expensive()
目前,我有一种幼稚的方法,可以简单地将测试函数参数化:
@pytest.mark.parametrize("A", A_ITEMS)
@pytest.mark.parametrize("B", B_ITEMS)
@pytest.mark.parametrize("C", C_ITEMS)
def test_each(F, A, B, C):
assert F.check(A, B, C)
这将测试F与A,B和C项的所有组合,但是它通过Expensive
夹具为每次测试构造了一个新的F
实例。更具体地说,它通过夹具F 为A,B和C的每种组合重建一个新的Expensive
。
这是非常低效的,因为当A和B的值发生变化时,我只需要构造一个新的Expensive
,而在所有C测试中它们都不是。
我想做的是以某种方式将F
固定装置与A_ITEMS
和B_ITEMS
列表组合在一起,以便F固定装置每次对实例运行一次仅实例化一个新实例。 C的值。
我的第一种方法是将A和B列表分成各自的固定装置,然后将它们与F固定装置组合在一起:
class Expensive:
def __init__(self, A, B):
# expensive set up
self.A = A
self.B = B
time.sleep(10)
def check(self, c):
return True # keep it simple
@pytest.fixture(params=[1,2,3])
def A(request):
return request.param
@pytest.fixture(params=[4,5,6])
def B(request):
return request.param
@pytest.fixture
def F(A, B):
return Expensive(a, b)
@pytest.mark.parametrize("C", C_ITEMS)
def test_each2(F, C):
assert F.check(C)
尽管这会测试所有组合,但不幸的是,这会为每个测试创建Expensive
的新实例,而不是将A和B的每个项目组合到一个可以为C的每个值重用的实例中。
我研究了间接灯具,但看不到将多个列表(即A和B项)发送到单个灯具的方法。
我可以使用pytest采取更好的方法吗?本质上,我想做的是使Expensive
的实例化次数最少,因为它取决于项A和B的值。
注意:我已经尝试简化此过程,但是实际情况是F代表创建新进程,A和B是该进程的命令行参数,而C只是传递给通过套接字进行处理。因此,我希望能够将C的每个值发送给该进程,而不必每次C更改时都重新创建它,但是很明显,如果A或B更改,我需要重新启动它(因为它们是该进程的命令行参数)。 / p>
答案 0 :(得分:0)
如果不选择使用pytest范围(如其他答案所述),则可以尝试缓存扩展对象,以便仅在需要时才构造它。
基本上,这扩展了问题中给出的建议,并为最后使用的参数提供了额外的静态缓存,以避免在不需要时创建新的Expansive
:
@pytest.fixture(params=A_ITEMS)
def A(request):
return request.param
@pytest.fixture(params=B_ITEMS)
def B(request):
return request.param
class FFactory:
lastAB = None
lastF = None
@classmethod
def F(cls, A, B):
if (A, B) != cls.lastAB:
cls.lastAB = (A, B)
cls.lastF = Expensive(A, B)
return cls.lastF
@pytest.fixture
def F(A, B):
return FFactory.F(A, B)
@pytest.mark.parametrize("C", C_ITEMS)
def test_each(F, C):
assert F.check(C)
答案 1 :(得分:0)
在这种情况下,我已经成功地使用了范围更广的灯具(模块或会话)作为每次测试灯具的“缓存”,这种情况下,灯具的“寿命”无法正确对齐摊销费用或其他费用。