2013-08-02 15 views
43

Używam py.test do przetestowania kodu DLL owiniętego w MyTester klasy Python. Dla celów walidacji muszę zarejestrować niektóre dane testowe podczas testów i później wykonać dalsze przetwarzanie. Ponieważ mam wiele testów _... chcę ponownie użyć tworzenia obiektów testowych (instancji MyTester) dla większości moich testów.py.test: Przekaż parametr do funkcji urządzenia

Ponieważ obiektem testującym jest ten, który uzyskał odniesienia do zmiennych i funkcji DLL, muszę przekazać listę zmiennych DLL do obiektu testera dla każdego z plików testowych (zmienne, które mają być rejestrowane są takie same dla plik testowy _...). Treść listy służy do rejestrowania określonych danych.

Mój pomysł jest zrobić to jakoś tak:

import pytest 

class MyTester(): 
    def __init__(self, arg = ["var0", "var1"]): 
     self.arg = arg 
     # self.use_arg_to_init_logging_part() 

    def dothis(self): 
     print "this" 

    def dothat(self): 
     print "that" 

# located in conftest.py (because other test will reuse it) 

@pytest.fixture() 
def tester(request): 
    """ create tester object """ 
    # how to use the list below for arg? 
    _tester = MyTester() 
    return _tester 

# located in test_...py 

# @pytest.mark.usefixtures("tester") 
class TestIt(): 

    # def __init__(self): 
    #  self.args_for_tester = ["var1", "var2"] 
    #  # how to pass this list to the tester fixture? 

    def test_tc1(self, tester): 
     tester.dothis() 
     assert 0 # for demo purpose 

    def test_tc2(self, tester): 
     tester.dothat() 
     assert 0 # for demo purpose 

Czy to możliwe, aby osiągnąć to w ten sposób, czy jest tam jeszcze bardziej elegancki sposób?

Zwykle mogę to zrobić dla każdej metody testowej z jakąś funkcją konfiguracji (styl xUnit). Ale chcę uzyskać pewnego rodzaju ponowne wykorzystanie. Czy ktokolwiek wie, czy jest to możliwe z urządzeniami w ogóle?

wiem, że mogę zrobić coś takiego: (od docs)

@pytest.fixture(scope="module", params=["merlinux.eu", "mail.python.org"]) 

Ale muszę do parametryzacji bezpośrednio w module testowym. Czy jest możliwy dostęp do atrybutu params urządzenia z modułu testowego?

Odpowiedz

45

Miałem podobny problem - mam urządzenie o nazwie test_package, a później chciałem móc przekazać opcjonalny argument do tego urządzenia podczas uruchamiania go w określonych testach. Na przykład:

@pytest.fixture() 
def test_package(request, version='1.0'): 
    ... 
    request.addfinalizer(fin) 
    ... 
    return package 

(To nie ma znaczenia dla tych celów, co robi osprzętu lub jaki typ obiektu zwrócona package) to.

Byłoby wówczas pożądane, aby w jakiś sposób użyć tego urządzenia w funkcji testowej w taki sposób, żebym mógł również podać argument tego urządzenia do użycia w tym teście. W tej chwili nie jest to możliwe, choć może to być dobra funkcja.

W międzyczasie łatwo było na tyle, aby moja Oprawa prostu zwrócić funkcję że nie wszystkie prace urządzenie poprzednio zrobił, ale pozwala mi określić version argument:

@pytest.fixture() 
def test_package(request): 
    def make_test_package(version='1.0'): 
     ... 
     request.addfinalizer(fin) 
     ... 
     return test_package 

    return make_test_package 

Teraz mogę użyj tego w mojej funkcji testowej, jak:

def test_install_package(test_package): 
    package = test_package(version='1.1') 
    ... 
    assert ... 

i tak dalej.

próbowali rozwiązanie OP został zmierza we właściwym kierunku, a jak na answer sugeruje @ hpk42 The MyTester.__init__ może po prostu zapisać się odniesienie do wniosku jak:

class MyTester(object): 
    def __init__(self, request, arg=["var0", "var1"]): 
     self.request = request 
     self.arg = arg 
     # self.use_arg_to_init_logging_part() 

    def dothis(self): 
     print "this" 

    def dothat(self): 
     print "that" 

Wtedy to wykorzystać do realizacji urządzenie jak :

@pytest.fixture() 
def tester(request): 
    """ create tester object """ 
    # how to use the list below for arg? 
    _tester = MyTester(request) 
    return _tester 

razie potrzeby klasa MyTester mogłyby zostać zrestrukturyzowane trochę tak, że jego atrybut .args mogą być aktualizowane po to został stworzony, aby dostosować zachowanie do individ testy.

+0

Dzięki za podpowiedź z funkcją wewnątrz urządzenia. Zajęło mi trochę czasu, zanim będę mógł nad tym popracować, ale jest to całkiem przydatne! – maggie

10

Dostęp do żądającego modułu/klasy/funkcji można uzyskać z funkcji urządzenia (a tym samym z własnej klasy Tester), patrz: interacting with requesting test context from a fixture function. Możesz więc zadeklarować niektóre parametry na klasie lub module, a urządzenie testujące może je odebrać.

+3

Wiem, że mogę zrobić coś takiego: (od docs) @ pytest.fixture (zakres = "module", params = [ "merlinux. eu "," mail.python.org "]) Ale muszę to zrobić w module testowym. Jak mogę dynamicznie dodawać parametry do urządzeń? – maggie

+1

Nie chodzi o to, aby * musieć interweniować z kontekstem żądania * z funkcji urządzenia, ale mieć dobrze zdefiniowany sposób przekazywania argumentów do funkcji urządzenia. Funkcja Fixture nie musi być świadoma typu kontekstu testowania żądania, tylko po to, aby móc odbierać argumenty o uzgodnionych nazwach. Na przykład chciałbyś móc napisać '@fixture def my_fixture (request)', a następnie '@pass_args (arg1 = ..., arg2 = ...) def test (my_fixture)' i uzyskać te argumenty w 'my_fixture() 'like this 'arg1 = request.arg1, arg2 = request.arg2'. Czy jest teraz coś takiego w py.test? –

61

To jest właściwie obsługiwane natywnie w py.test przez indirect parametrization.

W twoim przypadku, to masz:

@pytest.fixture 
def tester(request): 
    """Create tester object""" 
    return MyTester(request.param) 


class TestIt: 
    @pytest.mark.parametrize('tester', [['var1', 'var2']], indirect=True) 
    def test_tc1(self, tester): 
     tester.dothis() 
     assert 1 
+0

Ach, to całkiem miłe (myślę, że twój przykład może być trochę przestarzały - różni się od przykładów w oficjalnych dokumentach). Czy to jest stosunkowo nowa funkcja? Nigdy wcześniej tego nie spotkałem. Jest to również dobre rozwiązanie problemu - pod pewnymi względami lepsze niż moja odpowiedź. – Iguananaut

+0

Próbowałem używać tego rozwiązania, ale występowały problemy z przekazywaniem wielu parametrów lub używanie nazw zmiennych innych niż żądanie. Skończyłem z wykorzystaniem rozwiązania @Iguananaut. –

+14

** To powinna być zaakceptowana odpowiedź. ** [Oficjalna dokumentacja] (http://docs.pytest.org/en/latest/example/parametrize.html#deferring-the-setup-of-parametrized-resources) dla "pośredniego" argumentu słowa kluczowego jest wprawdzie skromny i nieprzyjazny, co prawdopodobnie wyjaśnia niejasność tej podstawowej techniki. Przeszukałem stronę py.test przy wielu okazjach dla tej właśnie funkcji - tylko po to, by wydobyć puste, starsze i oszołomione. Goryczka to miejsce znane jako ciągła integracja. _Dziękuję Odin za Stackoverflow._ –

Powiązane problemy