Mam jakieś dane testowe i chcę utworzyć test jednostkowy dla każdego elementu. Moim pierwszym pomysłem było zrobienie tego w ten sposób:
import unittest
l = [["foo", "a", "a",], ["bar", "a", "b"], ["lee", "b", "b"]]
class TestSequence(unittest.TestCase):
def testsample(self):
for name, a,b in l:
print "test", name
self.assertEqual(a,b)
if __name__ == '__main__':
unittest.main()
Minusem tego jest to, że obsługuje wszystkie dane w jednym teście. Chciałbym wygenerować jeden test dla każdego elementu w locie. Jakieś sugestie?
python
unit-testing
parameterized-unit-test
Peter Hoffmann
źródło
źródło
Odpowiedzi:
Nazywa się to „parametryzacją”.
Istnieje kilka narzędzi wspierających to podejście. Na przykład:
Wynikowy kod wygląda następująco:
Który wygeneruje testy:
Ze względów historycznych pozostawię oryginalną odpowiedź około roku 2008):
Używam czegoś takiego:
źródło
.__name__ =
włączyć.exact_method
testowanieif __name__ == '__main__'
warunku? Z pewnością powinien wyjść poza to, aby działać w czasie importu (pamiętając, że moduły Pythona są importowane tylko raz, nawet jeśli są importowane z kilku różnych miejsc)Używanie unittest (od 3.4)
Od wersji Python 3.4 standardowy
unittest
pakiet bibliotek masubTest
menedżera kontekstu.Zobacz dokumentację:
Przykład:
Możesz także określić niestandardowy komunikat i wartości parametrów, aby
subTest()
:Używanie nosa
Struktura testowania nosa obsługuje to .
Przykład (poniższy kod to cała zawartość pliku zawierającego test):
Dane wyjściowe polecenia nosetests:
źródło
Można to elegancko rozwiązać za pomocą Metaklas:
źródło
__new__
Metoda metaklasy jest wywoływana, gdy sama klasa jest zdefiniowana, a nie podczas tworzenia pierwszej instancji. Wyobrażam sobie, że ta metoda dynamicznego tworzenia metod testowych jest bardziej kompatybilna z introspekcją używanąunittest
do określania liczby testów w klasie (tj. Może skompilować listę testów, zanim stworzy instancję tej klasy).class TestSequence(unittest.TestCase, metaclass=TestSequenceMeta):[...]
dct
zamiastdict
? Używanie słów kluczowych jako nazw zmiennych jest mylące i podatne na błędy.Począwszy od wersji Python 3.4, w tym celu wprowadzono unittest. Szczegółowe informacje można znaleźć w dokumentacji . TestCase.subTest to menedżer kontekstu, który pozwala izolować potwierdzenia w teście, dzięki czemu niepowodzenie zostanie zgłoszone z informacją o parametrach, ale nie zatrzyma wykonania testu. Oto przykład z dokumentacji:
Wynikiem uruchomienia testowego byłoby:
Jest to również część unittest2 , więc jest dostępna dla wcześniejszych wersji Pythona.
źródło
setUp()
itearDown()
nie są przeprowadzane między podtestami.)self.setUp()
teoretycznie można je wywołać ręcznie z podtestu. Jeśli chodzi otearDown
, automatyczne wywołanie go na końcu może wystarczyć.load_tests to mało znany mechanizm wprowadzony w 2.7 do dynamicznego tworzenia TestSuite. Dzięki niemu możesz łatwo tworzyć sparametryzowane testy.
Na przykład:
Ten kod uruchomi wszystkie TestCases w TestSuite zwrócone przez load_tests. Mechanizm wykrywania nie uruchamia automatycznie żadnych innych testów.
Możesz także użyć dziedziczenia, jak pokazano na tym bilecie: http://bugs.python.org/msg151444
źródło
Można to zrobić za pomocą zapytania . Po prostu napisz plik
test_me.py
z zawartością:I uruchom test za pomocą polecenia
py.test --tb=short test_me.py
. Wynik będzie wyglądał następująco:To proste! Również pytest ma więcej funkcji, takich jak
fixtures
,mark
,assert
itp ...źródło
py.test
unittest
do py.test. Kiedyś miałemTestCase
klasy podstawowe, które były w stanie dynamicznie tworzyć dzieci z różnymi argumentami, które zapisywałyby jako zmienne klasowe ... co było trochę niewygodne.py.test
to yield_fixtures . Co może zrobić konfigurację , zwróć kilka użytecznych danych do testu, a po zakończeniu testu usuń . Urządzenia można również parametryzować .Użyj biblioteki ddt . Dodaje proste dekoratory do metod testowych:
Tę bibliotekę można zainstalować za pomocą
pip
. Nie wymaganose
i działa doskonale ze standardowymunittest
modułem bibliotecznym .źródło
Przydałoby się wypróbowanie biblioteki TestScenarios .
źródło
Istnieje również hipoteza, która dodaje testowanie oparte na fuzzach lub właściwościach: https://pypi.python.org/pypi/hypothesis
To bardzo skuteczna metoda testowania.
źródło
@given()
makra w najbardziej nieprzystosowanej klasie.Możesz użyć wtyczki nose-ittr (
pip install nose-ittr
).Bardzo łatwo jest zintegrować z istniejącymi testami, wymagane są minimalne zmiany (jeśli występują). Wspiera on także nos wtyczki wieloprocesorowe.
Nie to, że możesz również mieć funkcję dostosowywania
setup
na test.Możliwe jest również przekazanie
nosetest
parametrów, takich jak ichattrib
wbudowana wtyczka , w ten sposób można uruchomić tylko określony test z określonym parametrem:źródło
Używam metaklas i dekoratorów do generowania testów. Możesz sprawdzić moją implementację python_wrap_cases . Ta biblioteka nie wymaga żadnych ram testowych.
Twój przykład:
Dane wyjściowe konsoli:
Możesz także używać generatorów . Na przykład ten kod generuje wszystkie możliwe kombinacje testów z argumentami
a__list
ib__list
Dane wyjściowe konsoli:
źródło
Natknąłem ParamUnittest drugi dzień, kiedy patrząc na kod źródłowy do radonu ( Przykład użycia na repo github ). Powinien współpracować z innymi frameworkami rozszerzającymi TestCase (np. Nose).
Oto przykład:
źródło
WYNIK:
źródło
def add_test_methods
funkcją. Powinien byćdef _add_test_methods
, myślęPo prostu użyj metaklasy, jak pokazano tutaj;
Wynik:
źródło
Możesz używać klas
TestSuite
niestandardowychTestCase
.źródło
__init__
funkcji.Przekonałem się, że działa to dobrze dla moich celów, szczególnie jeśli muszę wygenerować testy, które nieznacznie różnicują procesy w zbiorze danych.
TestGenerator
Klasy mogą być wykorzystywane do tarła różne zestawy testów, takich jakTestCluster
.TestCluster
można uznać za implementacjęTestGenerator
interfejsu.źródło
To rozwiązanie działa z
unittest
inose
dla Python 2 i Python 3:źródło
Miałem problem z bardzo szczególnym stylem sparametryzowanych testów. Wszystkie nasze testy Selenium mogą być uruchamiane lokalnie, ale powinny być również możliwe do uruchomienia na kilku platformach w SauceLabs. Zasadniczo chciałem wziąć dużą liczbę już napisanych przypadków testowych i sparametryzować je przy jak najmniejszej możliwej zmianie kodu. Ponadto musiałem móc przekazać parametry do metody setUp, czegoś, czego nie widziałem w żadnym innym rozwiązaniu.
Oto, co wymyśliłem:
Dzięki temu wystarczyło dodać prosty dekorator @sauce_labs () do każdego standardowego starego TestCase, a teraz podczas ich uruchamiania są one pakowane i przepisywane, dzięki czemu wszystkie metody testowe są parametryzowane i zmieniane nazwy. LoginTests.test_login (self) działa jako LoginTests.test_login_internet_explorer_10.0 (self), LoginTests.test_login_internet_explorer_11.0 (self) i LoginTests.test_login_firefox_43.0 (self), a każdy z nich decyduje o tym, który parametr self / przeglądarka ma do wyboru platforma, z którą można się uruchomić, nawet w LoginTests.setUp, co jest kluczowe dla mojego zadania, ponieważ tam inicjowane jest połączenie z SauceLabs.
W każdym razie mam nadzieję, że może to pomóc komuś, kto chce przeprowadzić podobną „globalną” parametryzację swoich testów!
źródło
Odpowiedzi oparte na metaklasach nadal działają w Python3, ale zamiast
__metaclass__
atrybutu należy użyćmetaclass
parametru, jak w:źródło
Metaprogramowanie jest fajne, ale może się przydać. Większość rozwiązań utrudnia:
Tak więc moją pierwszą sugestią jest pójście prostą / jawną ścieżką (działa z dowolnym testerem):
Ponieważ nie powinniśmy się powtarzać, moja druga sugestia opiera się na odpowiedzi @ Javiera: objąć testy oparte na właściwościach. Biblioteka hipotez:
ma wiele innych interesujących funkcji (statystyki, dodatkowe wyniki testów, ...)
klasa TestSequence (unittest.TestCase):
Aby przetestować konkretne przykłady, wystarczy dodać:
Aby uruchomić tylko jeden konkretny przykład, możesz skomentować pozostałe przykłady (pod warunkiem, że pierwszy zostanie uruchomiony). Możesz użyć
@given(st.nothing())
. Inną opcją jest zastąpienie całego bloku:Ok, nie masz odrębnych nazw testów. Ale może potrzebujesz:
Zabawniejszy przykład
źródło
Bardzo późno na przyjęcie, ale miałem problemy z wykonaniem tych prac
setUpClass
.Oto wersja odpowiedzi @ Javiera, która daje
setUpClass
dostęp do dynamicznie przydzielanych atrybutów.Wyjścia
źródło
Wystarczy wrzucić kolejne rozwiązanie do mieszanki;)
Jest to faktycznie takie samo
parameterized
jak wspomniane powyżej, ale specyficzne dlaunittest
:Przykładowe użycie:
źródło
Oprócz używania setattr, możemy używać load_tests od Pythona 3.2. Proszę odnieść się do postu na blogu blog.livreuro.com/en/coding/python/how-to-generate-discoverable-unit-tests-in-python-dynamically/
źródło
Oto moje rozwiązanie. Uważam to za przydatne, gdy: 1. Powinien działać dla Unittest. Testuj i Unittest Discover 2. Przygotuj zestaw testów dla różnych ustawień parametrów. 3. Bardzo prosta brak zależności od innych pakietów
źródło
źródło