在pytest中的不同测试中仅使用某些夹具参数化

时间:2015-01-01 22:49:22

标签: python fixtures pytest

我有一个名为n_groups的夹具,我想在某些情况下参数化,但在其他情况下则不需要参数化。这样做的原因是因为我的MVC类数据模型的结构方式,我在"模型中尽可能多地测试"课程,但"控制器"课程不需要进行广泛的测试,因为我已经在"模型中完成了它。"因此,在控制器中运行带有所有参数化的测试是多余的,我想限制测试次数,从而限制测试时间。目前,为了测试我的控制器的初始化,生成了超过18,000个测试,运行需要42分钟!请参阅Travis-CI output

目前,我的解决方法是做,

# Contents of conftest.py
import pytest
import pandas as pd
import numpy as np

@pytest.fixture(scope='module', params=[2, 3],
                ids=['2_groups', '3_groups'])
def n_groups(request):
    """Number of phenotype groups.

    For testing that functions work when there's only 2 groups
    """
    return request.param

@pytest.fixture(scope='module')
def n_groups_fixed():
    """Fixed number of phenotype groups (3)"""
    return 3

然后,我将n_groupsn_groups_fixed传递给下一个灯具链,这些灯具会为测试创建数据。 outlierspooledsamplesn_samplesmetadata_phenotype_col灯具也已参数化,但不属于此问题的范围。

# Contents of conftest.py
@pytest.fixture(scope='module')
def groups(n_groups):
    """Phenotype group names"""
    return ['group{}'.format(i + 1) for i in np.arange(n_groups)]

@pytest.fixture(scope='module')
def groups_fixed(n_groups_fixed):
    """Phenotype group names"""
    return ['group{}'.format(i + 1) for i in np.arange(n_groups_fixed)]

@pytest.fixture(scope='module')
def groupby(groups, samples):
    return dict((sample, np.random.choice(groups)) for sample in samples)

@pytest.fixture(scope='module')
def groupby_fixed(groups_fixed, samples):
    return dict((sample, np.random.choice(groups_fixed)) for sample in samples)

@pytest.fixture(scope='module')
def metadata_data(groupby, outliers, pooled, samples,
                  n_samples,
                  metadata_phenotype_col):
    df = pd.DataFrame(index=samples)
    if outliers is not None:
        df['outlier'] = df.index.isin(outliers)
    if pooled is not None:
        df['pooled'] = df.index.isin(pooled)
    df[metadata_phenotype_col] = groupby
    df['subset1'] = np.random.choice([True, False], size=n_samples)
    return df

@pytest.fixture(scope='module')
def metadata_data_groups_fixed(groupby_fixed, outliers, pooled, samples,
                  n_samples,
                  metadata_phenotype_col):
    df = pd.DataFrame(index=samples)
    if outliers is not None:
        df['outlier'] = df.index.isin(outliers)
    if pooled is not None:
        df['pooled'] = df.index.isin(pooled)
    df[metadata_phenotype_col] = groupby_fixed
    df['subset1'] = np.random.choice([True, False], size=n_samples)
    return df

对于每个灯具都有*_fixed版本似乎相当麻烦。

测试的例子是数据模型中的广泛测试,测试n_groups的参数化,以及控制器内的不太广泛的测试,其仅测试一个参数化"使用groups_fixed(这些不是真正的测试,只是演示的例子):

# Contents of test_model.py
class TestModel(object):
    def test__init(metadata_data, ...):
        ...

    def test_plot(metadata_data_fixed, ...);
        ...

# Contents of test_controller.py
class TestController(object):
    def test__init(metadata_data_fixed, ...):
        ...

还有其他办法吗?我已经阅读了pytest的parameterize文档,但它似乎只是全局设置参数化,而不是基于每个测试。

我想做类似的事情:

# Contents of test_model.py
class TestModel(object):
    def test__init(metadata_data, ...):
        ...

    @pytest.mark.parameterize(n_groups=3)
    def test_plot(metadata_data, ...);
        ...

# Contents of test_controller.py
class TestController(object):
    @pytest.mark.parameterize(n_groups=3)
    def test__init(metadata_data_fixed, ...):
        ...

更新:在n_groups内添加TestController灯具并不起作用,即这不起作用:

# Contents of test_controller.py
class TestController(object):
    @pytest.fixture
    def n_groups():
        return 3

    def test__init(metadata_data_fixed, ...):
        ...

我不确定原因,因为这个灯具似乎应该覆盖n_groups中定义的全球conftest.py

2 个答案:

答案 0 :(得分:0)

我不确定你能用内置parametrize做到这一点,我认为你必须根据有关被测试方法的一些信息来实现自定义参数化方案(例如,如果一个类包含{ {1}}在其名称中,您将使用pytest_generate_tests hook以不同的方式对其进行参数化。可以找到一些示例here

答案 1 :(得分:0)

您的想法是正确的,使用参数化覆盖灯具值将在整个灯具链中生效。

下面的简化示例的工作方式是,它将对基于参数化的n_groups夹具的第一次测试运行两次,对于来自测试参数化的传递值,仅运行一次第二次测试。 (将-s添加到pytest调用中以查看打印输出)

# Contents of conftest.py
import pytest
import numpy as np

@pytest.fixture(params=[2, 4],
                ids=['2_groups', '4_groups'])
def n_groups(request):
    """Number of phenotype groups.

    For testing that functions work when there's only 2 groups
    """
    return request.param

@pytest.fixture
def groups(n_groups):
    """Phenotype group names"""
    return ['group{}'.format(i + 1) for i in np.arange(n_groups)]

def test_groups(groups):
    print(groups)


@pytest.mark.parametrize('n_groups', [3])
def test_groups_fixed(groups):
    print(groups)

关于为什么它在您的示例中不起作用,我怀疑这可能是由于夹具参数名称不同所致。当您使用固定装置n_groups_fixed但在测试参数化中调用参数n_groups时,它将不起作用。

相关问题