pytest参数化夹具与不同的情况

时间:2017-10-24 14:22:13

标签: python testing pytest

我有几个测试用例和测试函数,并且测试用例列表对于不同的函数是不同的。这可以通过pytest.mark.parametrize轻松完成。我需要的是加载资源(在我的情况下是一个文件),我希望每个测试会话只加载一次这个文件并缓存。

下面举例说明我想要的内容。它正在工作,但我想找到一种方法来使用pytest fixtures或其他一些缓存机制,这样我就不必自己进行缓存并在每个测试函数中都有pars=load_file(pars)行。

有人可以用pytest解释如何做到这一点吗?

import pytest

case_1 = dict(label='case_1', spam=1)
case_2 = dict(label='case_2', spam=2)
case_3 = dict(label='case_3', spam=3)

_cache = {}


def load_file(pars):
    if pars['label'] in _cache:
        print('load_file from cache', pars)
        return _cache[pars['label']]
    else:
        print('load_file loading', pars)
        pars['file'] = pars['label'] + ' spam!'
        _cache[pars['label']] = pars
        return pars


@pytest.mark.parametrize('pars', [case_1, case_2])
def test_a(pars):
    pars = load_file(pars)
    print('test_a', pars)


@pytest.mark.parametrize('pars', [case_2, case_3])
def test_b(pars):
    pars = load_file(pars)
    print('test_b', pars)


@pytest.mark.parametrize('pars', [case1, case_2, case_3])
def test_c(pars):
    pars = load_file(pars)
    print('test_c', pars)

### more tests here for various combinations of test cases

2 个答案:

答案 0 :(得分:0)

第一个也是最明显的解决方案是使用会话范围的灯具。但是,它需要重新构建测试文件,并提前加载所有已知文件。

return database.update({ref : parseInt(number)})
    .then(() => {
        // Each then() should return a value or throw
        return 'Update successful';
    })
    .catch(error => {
        // handle the error however you like
        console.error(error);
    });

请注意间接参数化。这意味着将准备import pytest @pytest.fixture(scope='session') def pars_all(): cache = {} for case in [case_1, case_2, case_3]: cache[case['label']] = 'case {} content'.format(case) yield cache # optionally destroy or unload or unlock here. @pytest.fixture(scope='function') def pars(request, pars_all): label = request.param yield pars_all[label] @pytest.mark.parametrize('pars', ['case_1', 'case_2'], indirect=True) def test(pars): pass 灯具,获取pars中的参数值。参数名称和灯具必须共享相同的名称。

对于所有测试,会话范围的装置(或模块范围,或类型范围,如果您愿意)将只准备一次。重要的是要注意,更宽的固定装置可用于更窄的范围或相同范围的固定装置,但不能用于相反的方向。

如果案例定义不明确,那就容易了,只需按需填充缓存:

request.param

注意,import pytest @pytest.fixture(scope='session') def pars_all(): yield {} @pytest.fixture(scope='function') def pars(request, pars_all): label = request.param if label not in pars_all: print('[[[{}]]]'.format(request.param)) pars_all[label] = 'content of {}'.format(label) yield pars_all[label] @pytest.mark.parametrize('pars', ['case_1', 'case_2'], indirect=True) def test_1(pars): print(pars) @pytest.mark.parametrize('pars', ['case_1', 'case_3'], indirect=True) def test_2(pars): print(pars) 对象只创建一次,因为它是会话范围的,并且在所有测试和/或之间共享。 callspecs。因此,如果一个灯具添加了一些东西,其他灯具也会看到它。您可以注意到{}

case_1的重用方式
test_2

答案 1 :(得分:0)

在文件解析功能中简单地使用@lru_cache也可以实现缓存技巧:

@lru_cache(maxsize=3)
def load_file(file_name):
    """ This function loads the file and returns contents"""
    print("loading file " + file_name)
    return "<dummy content for " + file_name + ">"

通过使用pytest-cases将测试功能与测试用例分开(我是作者!),您还可以获得相同的结果,同时使整个代码更具可读性(?): / p>

from functools import lru_cache
from pytest_cases import CaseData, cases_data, CaseDataGetter, case_tags


@lru_cache(maxsize=3)
def load_file(file_name):
    """ This function loads the file and returns contents"""
    print("loading file " + file_name)
    return "<dummy content for " + file_name + ">"

def case_1() -> CaseData:
    ins = load_file('file1')
    outs, err = None, None
    return ins, outs, err

def case_2() -> CaseData:
    ins = load_file('file2')
    outs, err = None, None
    return ins, outs, err

def case_3() -> CaseData:
    ins = load_file('file3')
    outs, err = None, None
    return ins, outs, err

@cases_data(cases=[case_1, case_2])
def test_a(case_data: CaseDataGetter):
    # 1- Grab the test case data
    i, expected_o, expected_e = case_data.get()

    # 2- Use it
    # see pytest-cases usage page for suggestions


@cases_data(cases=[case_2, case_3])
def test_b(case_data: CaseDataGetter):
    # 1- Grab the test case data
    i, expected_o, expected_e = case_data.get()

    # 2- Use it
    # see pytest-cases usage page for suggestions


@cases_data(cases=[case_1, case_2, case_3])
def test_c(case_data: CaseDataGetter):
    # 1- Grab the test case data
    i, expected_o, expected_e = case_data.get()

    # 2- Use it
    # see pytest-cases usage page for suggestions

收益:

test_memoize.py::test_a[case_1] loading file file1
PASSED
test_memoize.py::test_a[case_2] loading file file2
PASSED
test_memoize.py::test_b[case_2] PASSED
test_memoize.py::test_b[case_3] loading file file3
PASSED
test_memoize.py::test_c[case_1] PASSED
test_memoize.py::test_c[case_2] PASSED
test_memoize.py::test_c[case_3] PASSED

最后,请注意,根据您的用例,您可能希望切换到案例生成器功能,这将更具可读性并且supports caching too。如果您不想明确地对案例进行硬编码,也请查看tags & filters