2016-05-10 11 views
8

Przeczytałem kilka sprzecznych porad dotyczących korzystania z metody assert w teście jednostek Pythona. Nie widzę szkody w nieudanej próbie, jeśli warunek wstępny, którego test opiera się na niepowodzeniu.Jaki jest poprawny sposób zgłaszania błędu w unittest Python w metodzie setUp?

Na przykład:

import unittest 

class MyProcessor(): 
    """ 
    This is the class under test 
    """ 

    def __init__(self): 
     pass 

    def ProcessData(self, content): 
     return ['some','processed','data','from','content'] # Imagine this could actually pass 

class Test_test2(unittest.TestCase): 

    def LoadContentFromTestFile(self): 
     return None # Imagine this is actually doing something that could pass. 

    def setUp(self): 
     self.content = self.LoadContentFromTestFile() 
     self.assertIsNotNone(self.content, "Failed to load test data") 
     self.processor = MyProcessor() 

    def test_ProcessData(self): 
     results = self.processor.ProcessData(self.content) 
     self.assertGreater(results, 0, "No results returned") 

if __name__ == '__main__': 
    unittest.main() 

To wydaje się rozsądnym rozwiązaniem dla mnie to upewnij się, że test jest w stanie uruchomić. Gdy to nie ze względu na stan instalacji otrzymujemy:

F 
====================================================================== 
FAIL: test_ProcessData (__main__.Test_test2) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "C:\Projects\Experiments\test2.py", line 21, in setUp 
    self.assertIsNotNone(self.content, "Failed to load test data") 
AssertionError: unexpectedly None : Failed to load test data 

---------------------------------------------------------------------- 
Ran 1 test in 0.000s 

FAILED (failures=1) 

Odpowiedz

9

Celem setUp jest zmniejszenie Boilerplate code która tworzy się pomiędzy testami w klasie testowej podczas fazy Arrange

w fazie zorganizować Państwu:.. wszystko konfiguracja potrzebna do jazdy badanego kodu obejmuje to wszelkie inicjalizacji zależności, mocks i danych potrzebnych do testu, aby uruchomić

. W oparciu o powyższe paragrafy nie powinieneś podawać niczego w swojej metodzie setUp.

Tak jak wspomniano wcześniej; Jeśli nie możesz utworzyć warunku testowego, test zostanie przerwany. Aby uniknąć takich sytuacji, Roy Osherove napisał świetną książkę pod tytułem: The Art Of Unit Testing (Dla pełnego ujawnienia Lior Friedman (był szefem Roya) jest moim przyjacielem i blisko z nimi współpracowałem przez ponad 2 lata, więc jestem trochę stronniczy ...)

Zasadniczo istnieje tylko kilka powodów do interakcji z zasobami zewnętrznymi podczas fazy Rozmieszczenia (lub z rzeczami, które mogą powodować wyjątek), większość z nich (jeśli nie wszystkie) są powiązane w testach integracyjnych.

Powrót do przykładu; Istnieje wzorzec do strukturowania testów, w których należy załadować zewnętrzny zasób (dla wszystkich/większości z nich). Tylko notatkę boczną; zanim zdecydujesz się zastosować ten wzorzec, upewnij się, że nie możesz mieć tej zawartości jako statycznego zasobu w klasie UT, jeśli inne klasy testowe muszą użyć tego zasobu, wyodrębnij ten zasób do modułu.

Poniższy wzór zmniejszyć możliwość porażki, ponieważ masz mniej połączeń do zasobów zewnętrznych:

class TestClass(unittest.TestCase): 

    def setUpClass(self): 
     # since external resources such as other servers can provide a bad content 
     # you can verify that the content is valid 
     # then prevent from the tests to run 
     # however, in most cases you shouldn't. 
     self.externalResourceContent = loadContentFromExternalResource() 


    def setUp(self): 
     self.content = self.copyContentForTest() 

Plusy:

  1. mniejsze szanse na niepowodzenie
  2. zapobiec zachowanie brak spójności (1 coś/jeden edytował zewnętrzny zasób 2. nie udało Ci się załadować zewnętrznego zasobu w niektórych twoich testach)
  3. szybsze wykonanie

Wady:

  1. Kod jest bardziej złożona
5

setUp nie jest dla twierdząc warunków wstępnych, ale tworzących im. Jeśli twój test nie jest w stanie stworzyć niezbędnego urządzenia, jest on uszkodzony, a nie uszkodzony.

+0

Więc jak należy podkreślić, że w zautomatyzowanym środowisku kompilacji? –

+3

@JonCage IMHO, jeśli naprawdę potrzebujesz przetestować warunki wstępne, powinieneś napisać test dla nich i nie używać 'setUp()', aby potwierdzić, że twoje warunki wstępne są prawidłowe. Dodaj test, taki jak 'test_load_fixture (self): self.assertIsNotNone (self.content," Nie udało się załadować danych testowych ")' i będziesz mieć błąd dla tego testu i niepowodzenie dla każdego testu, który używa 'self.content '. –

2

Nie ma tutaj poprawnej lub złej odpowiedzi, zależy to od tego, co testujesz i od tego, jak kosztowne jest konfigurowanie testów. Niektóre testy są zbyt niebezpieczne, aby umożliwić wykonanie prób, jeśli dane nie są zgodne z oczekiwaniami, niektóre muszą pracować z tymi danymi.

Możesz używać asercji w setUp, jeśli chcesz sprawdzić między testami dla poszczególnych warunków, co może pomóc zmniejszyć liczbę powtórzeń w testach. Jednak powoduje również, że przenoszenie metod testowania między klasami lub plikami jest trochę trudniejsze, ponieważ będą wymagać posiadania równoważnego ustawienia. Może także przesuwać granice złożoności w przypadku testerów mniej doświadczonych w kodowaniu.

Trochę czysto, aby przeprowadzić test, który indywidualnie sprawdza te warunki uruchamiania i uruchamia je najpierw, mogą one nie być potrzebne pomiędzy poszczególnymi testami. Jeśli zdefiniujesz to jako test_01_check_preconditions, zostanie to wykonane przed każdą inną metodą testową, nawet jeśli reszta jest losowa. Można również użyć dekoratorów unittest2.skip w określonych warunkach.

Lepszym rozwiązaniem jest użycie addCleanup w celu upewnienia się, że stan został zresetowany, zaletą jest to, że nawet jeśli test się nie powiedzie, to nadal jest uruchamiany, możesz również uczynić oczyszczanie bardziej świadomym konkretnej sytuacji, jak to zdefiniowałeś w kontekst twojej metody testowej.

Nic nie stoi na przeszkodzie, aby zdefiniować metody przeprowadzania typowych sprawdzeń w klasie klasy antywirusowej i wywoływania ich w setUp lub test_metod, co może pomóc w utrzymaniu złożoności w zdefiniowanych i zarządzanych obszarach.

Nie ulegaj pokusie podklasowania unittest2 poza prostą definicją testu, widziałem ludzi, którzy próbują to zrobić, aby testy były proste i wprowadzały całkowicie nieoczekiwane zachowanie.

Domyślam się, że prawdziwy powrót do domu to, jeśli to robisz, wiesz, dlaczego chcesz go użyć i upewnić się, że dokumentujesz swoje powody, to prawdopodobnie jest w porządku, jeśli nie masz pewności, wybierz najprostszą i najłatwiejszą do zrozumienia opcję, ponieważ testy są bezużyteczne, jeśli nie są łatwe do zrozumienia.

3

Z Python Standard Library Documentation: metody

„Jeśli metoda setup() podnosi wyjątek, gdy test jest uruchomiony, ramy rozważy test ponieśli błąd i runTest() będzie Jeśli setUp() się powiedzie, metoda tearDown() zostanie uruchomiona niezależnie od tego, czy runTest() powiodło się, czy nie.Takie środowisko pracy dla kodu testowego nazywa się urządzeniem."

Wyjątek twierdzenie w metodzie setup() będą uważane za błąd przez unittest ram. Test nie zostanie wykonany.

2

Jest jeden powód, dla którego chcesz uniknąć twierdzeń w A setUp(). Jeśli setUp nie powiedzie się, twoja tearDown będzie , a nie wykonana.

Jeśli ustawisz zestaw rekordów bazy danych dla instancji i twoje usunięcie spowoduje skasowanie tych rekordów, wówczas te rekordy nie zostaną usunięte.

Z tego fragmentu:

import unittest 

class Test_test2(unittest.TestCase): 

    def setUp(self): 
     print 'setup' 
     assert False 

    def test_ProcessData(self): 
     print 'testing' 

    def tearDown(self): 
     print 'teardown' 

if __name__ == '__main__': 
    unittest.main() 

uruchomić tylko na setUp():

$ python t.py 
setup 
E 
====================================================================== 
ERROR: test_ProcessData (__main__.Test_test2) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "t.py", line 7, in setUp 
    assert False 
AssertionError 

---------------------------------------------------------------------- 
Ran 1 test in 0.000s 

FAILED (errors=1) 
Powiązane problemy