2013-04-04 11 views
5

Ściśle związane:In python, is there a good idiom for using context managers in setup/teardownpy.test - jak użyć menedżera kontekstowe w funcarg/urządzenia


mam menedżera kontekstowe, które jest używane w badaniach, aby ustalić czas/strefę czasową. Chcę go mieć w pytce funcarg (lub urządzeniu, używamy pytest 2.2.3 ale mogę tłumaczyć wstecz). Mogę to zrobić:

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) 

... ale jest trochę nieprzyjemnie. W powiązanym Q jsbueno zauważa: Problem polega na tym, że twój kod nie ma przepisu na prawidłowe wywołanie metody obiektu __exit__, jeśli wystąpi wyjątek.

His answer wykorzystuje podejście metaclass. Ale nie jest to użyteczne w pytest, gdzie często testy są po prostu funkcjami, a nie klasami. Więc jaki byłby najlepszy sposób rozwiązania tego problemu? Coś związanego z runtest hooks?

Odpowiedz

0

Obawiam się, że obecnie nie ma eleganckiego sposobu korzystania z menedżerów kontekstów w urządzeniach. Jednak finalizatory będzie działać, jeśli test się nie powiedzie:

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') 

Jeśli uruchomić to z pytest -s widać, że wezwanie __exit__() dzieje.

+1

Moją obawą nie jest to, że '__exit__' nie może być wywołany, ale że nie zostanie wywołany z [prawymi wartościami] (http://docs.python.org/2/reference/datamodel .html # menedżerów kontekstów). '__exit__' jest zwykle wywoływane z wartościami odnoszącymi się do dowolnego wyjątku podniesionego w bloku' with' (w tym przypadku byłby to obiekt testowy). – pfctdayelise

9

Od 2.4, py.test ma wsparcie dla stylu stylu yield. Moglibyśmy bezpośrednio użyć kontekstu with.

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

Od 3,0 py.test przestarzałe użycie @pytest.yield_fixture. Możemy użyć @pytest.fixture jako menedżera kontekstu bezpośrednio.

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

Myślę, że urządzenia stylowe są przestarzałe? –

+1

@NeilG Dzięki za komentarz. Zaktualizowałem odpowiedź na zmiany w Pytest 3.0. –