2013-04-04 23 views
5

Strettamente legato:In python, is there a good idiom for using context managers in setup/teardownpy.test - come utilizzare un gestore di contesto in un funcarg/apparecchio


Ho un gestore di contesto che viene utilizzato nei test per fissare l'ora/fuso orario. Voglio averlo in un funcarg pytest (o fixture, stiamo usando pytest 2.2.3 ma posso tradurre all'indietro). Potrei solo fare questo:

def pytest_funcarg__fixedTimezone(request): 
    # fix timezone to match Qld, no DST to worry about and matches all 
    # Eastern states in winter. 
    fixedTime = offsetTime.DisplacedRealTime(tz=' Australia/Brisbane') 

    def setup(): 
     fixedTime.__enter__() 
     return fixedTime 

    def teardown(fixedTime): 
     # this seems rather odd? 
     fixedTime.__exit__(None, None, None) 

... ma è un po 'icky. Nel relativo Q jsbueno si fa notare: Il problema è che il proprio codice non prevede di chiamare correttamente il metodo __exit__ dell'oggetto se si verifica un'eccezione.

His answer utilizza un approccio metaclass. Ma questo non è così utile per pytest dove spesso i test sono solo funzioni, non classi. Quindi quale sarebbe il modo più pazzo per risolvere questo? Qualcosa che coinvolge runtest hooks?

risposta

0

Temo che non ci sia attualmente un modo elegante di utilizzare i gestori di contesto nei dispositivi. Tuttavia i finalizzatori verranno eseguiti se il test fallisce:

import contextlib, pytest 

@contextlib.contextmanager 
def manager(): 
    print 'manager enter' 
    yield 42 
    print 'manager exit' 

@pytest.fixture 
def fix(request): 
    m = manager() 
    request.addfinalizer(lambda: m.__exit__(None, None, None)) 
    return m.__enter__() 

def test_foo(fix): 
    print fix 
    raise Exception('oops') 

Se si esegue questo con pytest -s vedrete che la chiamata __exit__() accade.

+1

La mia preoccupazione non è che il '__exit__' non può essere chiamato, ma che non sarà chiamato con i valori giusti [] (http://docs.python.org/2/reference/datamodel .html # contesto-manager). '__exit__' viene normalmente chiamato con valori relativi a qualsiasi eccezione sollevata nel blocco' with' (o in questo caso sarebbe il corpo del test). – pfctdayelise

9

Dal 2.4, py.test ha il supporto di tipo yield. Potremmo usare direttamente un contesto with all'interno di esso.

@pytest.yield_fixture 
def passwd(): 
    with open("/etc/passwd") as f: 
     yield f.readlines() 

Dal 3.0, py.test deprecato l'uso @pytest.yield_fixture. Potremmo utilizzare direttamente @pytest.fixture come gestore del contesto.

@pytest.fixture 
def passwd(): 
    with open("/etc/passwd") as f: 
     yield f.readlines() 
+0

Penso che i dispositivi stile rendimento siano deprecati? –

+1

@NeilG Grazie per il tuo commento. Ho aggiornato la risposta per le modifiche pytest 3.0. –

Problemi correlati