2015-01-01 14 views
6

Ho un dispositivo chiamato n_groups che vorrei parametrizzare in alcuni casi, ma non in altri. La ragione di questo è dovuta al modo in cui è strutturato il mio modello di dati simile a MVC, provo il più possibile nelle classi "modello", ma le classi "controller" non hanno bisogno di test così estesi perché ho già fatto nel "modello". Quindi l'esecuzione dei test con tutte le parametrizzazioni è ridondante nel controller e vorrei limitare il numero di test e quindi il tempo di test. Attualmente per testare l'inizializzazione del mio controller, vengono generati oltre 18.000 test e ci vogliono 42 minuti per essere eseguito! Vedi lo Travis-CI output.Utilizzare solo alcune parametrizzazioni di fixture in diversi test in pytest

Attualmente, il mio soluzione è quello di fare,

# 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 

Poi, passo sia n_groups o n_groups_fixed alla prossima catena di apparecchi che creano i dati per il test. Gli apparecchi outliers, , samples, n_samples e metadata_phenotype_col sono anche parametrizzati, ma non rientrano nell'ambito di questa domanda.

# 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 

sembra piuttosto ingombrante per avere una versione *_fixed per ciascuno di questi apparecchi.

Esempi di prove sarebbero una serie di test all'interno del modello dati testare entrambi parametrizzazioni n_groups, e meno estesa prova all'interno del regolatore, che verifica una sola "parametrizzazione" utilizzando groups_fixed (queste non sono prove reali, basta esempi per dimostrazione):

# 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, ...): 
     ... 

C'è un altro modo per farlo? Ho letto la documentazione di pytest parameterize, ma sembra solo impostare le parametrizzazioni a livello globale e non in base al test.

mi piacerebbe fare qualcosa di simile:

# 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, ...): 
     ... 

UPDATE: Aggiunta di un n_groups apparecchio all'interno TestController non aiuta, vale a dire questo non funziona:

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

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

Sono non so perché, perché sembra che questa apparecchiatura dovrebbe sovrascrivere il globale n_groups definito in conftest.py

risposta

0

Non sono sur e puoi farlo con l'integrato parametrize, penso che dovrai implementare uno schema di parametrizzazione personalizzato basato su alcune informazioni sul metodo testato (ad esempio, se una classe contiene Controller nel suo nome, lo si parametrizzerà in modo diverso), usando il pytest_generate_tests hook. Alcuni esempi possono essere trovati here.

+0

Grazie! Questo funziona per 'TestController' perché posso averlo nel file' test_controller.py', e si applicherebbe a tutti i test nel file. Per 'TestModel', dovrei controllare' metafunc.function .__ name__' per controllare lì? Sembra che questo genere di cose possa essere incapsulato in un decoratore per le funzioni di test. Sai se una tale funzionalità è pianificata in 'pytest'? –

+0

Sì, controlla metafunc.function .__ name__ potrebbe funzionare. Non penso che ci siano piani per implementarlo come un decoratore incorporato, però. –