Masz rację, twoje testy nie powinny sprawdzać, czy random
moduł wykonuje swoją pracę; unittest powinien testować tylko samą klasę, a nie sposób interakcji z innym kodem (który powinien być testowany osobno).
Jest oczywiście całkowicie możliwe, że Twój kod używa random.randint()
niewłaściwie; lub random.randrange(1, self._sides)
zamiast tego dzwonisz, a twoja kość nigdy nie rzuca najwyższej wartości, ale byłby to inny rodzaj błędu, który nie byłby w stanie złapać przy najmniejszym poziomie. W takim przypadku die
urządzenie działa zgodnie z przeznaczeniem, ale sam projekt był wadliwy.
W tym przypadku użyłbym wyśmianie aby wymienić się randint()
funkcji, a jedynie sprawdzić, czy został on nazywany poprawnie. Python 3.3 i nowsze wersje są dostarczane z unittest.mock
modułem do obsługi tego typu testów, ale można zainstalować mock
pakiet zewnętrzny na starszych wersjach, aby uzyskać dokładnie taką samą funkcjonalność
import unittest
try:
from unittest.mock import patch
except ImportError:
# < python 3.3
from mock import patch
@patch('random.randint', return_value=3)
class TestDice(unittest.TestCase):
def _make_one(self, *args, **kw):
from die import Die
return Die(*args, **kw)
def test_standard_size(self, mocked_randint):
die = self._make_one()
result = die.roll()
mocked_randint.assert_called_with(1, 6)
self.assertEqual(result, 3)
def test_custom_size(self, mocked_randint):
die = self._make_one(sides=42)
result = die.roll()
mocked_randint.assert_called_with(1, 42)
self.assertEqual(result, 3)
if __name__ == '__main__':
unittest.main()
Dzięki drwiom test jest teraz bardzo prosty; tak naprawdę są tylko 2 przypadki. Domyślny przypadek dla 6-stronnej matrycy i niestandardowy przypadek po bokach.
Istnieją inne sposoby tymczasowego zastąpienia randint()
funkcji w globalnej przestrzeni nazw Die
, ale mock
moduł czyni to najłatwiejszym. @mock.patch
Dekorator tutaj odnosi się do wszystkich metod badań w przypadku badania; do każdej metody testowej przekazywany jest dodatkowy argument - wyśmiewana random.randint()
funkcja, dzięki czemu możemy testować przeciwko próbce, aby sprawdzić, czy rzeczywiście została poprawnie wywołana. W return_value
Określa argumentów co wrócił z mock kiedy to się nazywa, więc możemy sprawdzić, czy die.roll()
metoda rzeczywiście wrócił „random” rezultat do nas.
Użyłem tutaj kolejnej najlepszej praktyki Pythona: zaimportuj testowaną klasę w ramach testu. _make_one
Metoda działa importowanie i konkretyzacji w teście , tak że test moduł nadal będzie ładować nawet jeśli popełnił błąd składni lub inny błąd, który będzie zapobiegać oryginalny moduł do importu.
W ten sposób, jeśli popełnisz błąd w samym kodzie modułu, testy będą nadal uruchamiane; po prostu zawiodą, informując o błędzie w kodzie.
Dla jasności powyższe testy są wyjątkowo uproszczone. Naszym celem nie jest na przykład testowanie random.randint()
przy użyciu odpowiednich argumentów. Zamiast tego celem jest przetestowanie, czy jednostka daje prawidłowe wyniki przy określonych danych wejściowych, przy czym dane wejściowe obejmują wyniki innych jednostek, które nie są testowane. Wyśmiewając random.randint()
metodę, możesz przejąć kontrolę nad kolejnymi danymi wejściowymi do swojego kodu.
W rzeczywistych testach rzeczywisty kod w testowanym urządzeniu będzie bardziej złożony; związek z danymi wejściowymi przekazywanymi do interfejsu API i sposób wywoływania innych jednostek może być nadal interesujący, a kpina zapewni dostęp do wyników pośrednich, a także umożliwi ustawienie wartości zwracanych dla tych wywołań.
Na przykład w kodzie, który uwierzytelnia użytkowników na podstawie usługi OAuth2 innej firmy (interakcja wieloetapowa), chcesz przetestować, czy Twój kod przekazuje odpowiednie dane do tej usługi innej firmy i pozwala wyśmiewać różne odpowiedzi na błędy, które Usługa innej firmy powróci, umożliwiając symulację różnych scenariuszy bez konieczności samodzielnego budowania pełnego serwera OAuth2. W tym miejscu ważne jest przetestowanie, czy informacje z pierwszej odpowiedzi zostały poprawnie obsłużone i zostały przekazane do wywołania drugiego etapu, więc chcesz zobaczyć, czy fałszywa usługa jest wywoływana poprawnie.