在参数化的夹具中缓存测试数据

Posted

技术标签:

【中文标题】在参数化的夹具中缓存测试数据【英文标题】:Caching test data in parameterized fixtures 【发布时间】:2021-12-08 09:10:18 【问题描述】:

我有各种使用通用数据的测试用例。我使用pytest 夹具来缓存测试数据并加快测试速度。

例如:

@pytest.fixture(scope='module')
def data():
    large_data = download('XYZ')
    return large_data

def test_foo(data):
    pass

def test_bar(data):
    pass

我想将测试扩展到两个数据集。蛮力解决方案是:

@pytest.fixture(scope='module')
def data1():
    large_data = download('XYZ')
    return large_data

@pytest.fixture(scope='module')
def data2():
    large_data = download('ABC')
    return large_data

def test_foo1(data1):
    pass

def test_foo2(data2):
    pass

def test_bar1(data1):
    pass

def test_bar2(data2):
    pass

现在的问题是test_bar 是通用的。从某种意义上说,测试程序独立于数据。因此,复制它是一个坏主意。

所以,我决定使用间接参数如下:

@pytest.fixture(scope='module')
def data(request):
    if request.param == 1:
       large_data = download('XYZ')
    if request.param == 2:
       large_data = download('ABC')
    return large_data

@pytest.mark.parametrize('data', [1], indirect=True)
def test_foo1(data):
    pass

@pytest.mark.parametrize('data', [2], indirect=True)
def test_foo2(data):
    pass

@pytest.mark.parametrize('data', [1, 2], indirect=True)
def test_bar(data):
    pass

但现在我失去了缓存优势。下载数据以供测试。如何告诉 pytest 缓存参数化夹具的数据?

【问题讨论】:

问题显然出在测试顺序上——因为fixture是用不同的参数调用的,它不能在模块中只调用一次,因为它通常是使用模块范围的fixture来完成的。最好的选择可能是缓存数据并在下次访问时重复使用。 【参考方案1】:

我找到了一个(非理想的)解决方案。这个想法是为每个测试数据定义一个固定装置(不能很好地扩展),然后使用“包装器”参数化固定装置来返回它们的值。

@pytest.fixture(scope='module')
def data1():
    large_data = download('XYZ')
    return large_data

@pytest.fixture(scope='module')
def data2():
    large_data = download('ABC')
    return large_data

@pytest.fixture(scope='module')
def data(request):
    
    return request.getfixturevalue(request.param)

def test_foo1(data1):
    pass

def test_foo2(data2):
    pass

@pytest.mark.parametrize('data', ['data1', 'data2'], indirect=True)
def test_bar(data):
    pass

我已经验证过(至少在这个例子中)每个数据集都被下载了一次,并且只下载了一次。不过,我很想知道是否有“更清洁”的解决方案。

【讨论】:

以上是关于在参数化的夹具中缓存测试数据的主要内容,如果未能解决你的问题,请参考以下文章

为 Google 测试夹具指定构造函数参数

将参数传递给夹具函数

如何在大型项目中管理用于验收测试的测试数据夹具?

在单元测试之间恢复数据库:数据库仍在使用中

Django 不会为某些测试用例重新加载夹具

如何在 symfony WebTestCase 的测试中按夹具类型获取教义夹具参考?