Mam kilka klas, które zajmują się walidacją wartości. Na przykład RangeValidator
klasa sprawdza, czy wartość mieści się w określonym zakresie.
Każda klasa walidatora zawiera dwie metody: is_valid(value)
która zwraca wartość True
lub False
zależy od niej i ensure_valid(value)
która sprawdza określoną wartość i albo nie robi nic, jeśli wartość jest poprawna, albo zgłasza określony wyjątek, jeśli wartość nie pasuje do wstępnie zdefiniowanych reguł.
Obecnie z tą metodą związane są dwa testy jednostkowe:
Ten, który przekazuje niepoprawną wartość i zapewnia, że wyjątek został zgłoszony.
def test_outside_range(self): with self.assertRaises(demo.ValidationException): demo.RangeValidator(0, 100).ensure_valid(-5)
Ten, który przekazuje prawidłową wartość.
def test_in_range(self): demo.RangeValidator(0, 100).ensure_valid(25)
Chociaż drugi test wykonuje swoją pracę - nie powiedzie się, jeśli zostanie zgłoszony wyjątek, a powiedzie się, jeśli ensure_valid
niczego nie wyrzuci - fakt, że w środku nie ma żadnych assert
znaków, wygląda dziwnie. Ktoś, kto czyta taki kod, od razu zadaje sobie pytanie, dlaczego istnieje test, który wydaje się nic nie robić.
Czy jest to obecna praktyka podczas testowania metod, które nie zwracają wartości i nie wywołują skutków ubocznych? Czy powinienem przepisać test w inny sposób? Lub po prostu wstaw komentarz wyjaśniający, co robię?
źródło
self
referencji) i nie zwraca żadnego wyniku, nie jest to funkcja czysta.void
w wielu językach i ma głupie reguły). Alternatywnie, możesz mieć nieskończoną pętla (która działa nawet wtedy, gdy „nie zwraca wyniku” naprawdę oznacza, że nie zwraca wyników.unit -> unit
w dowolnym języku, która uważa jednostkę za standardowy typ danych zamiast czegoś magicznie specjalnego. Niestety po prostu zwraca jednostkę i nic więcej nie robi.Odpowiedzi:
Większość frameworków testowych ma wyraźne stwierdzenie „nie rzuca”, np. Jasmine ma,
expect(() => {}).not.toThrow();
a nUnit i przyjaciele też je mają.źródło
Zależy to silnie od używanego języka i frameworka. Mówiąc w kategoriach
NUnit
, istniejąAssert.Throws(...)
metody. Możesz przekazać im metodę lambda:który jest wykonywany w ramach
Assert.Throws
. Wywołanie do lambda najprawdopodobniej zostanie otoczonetry { } catch { }
blokiem, a potwierdzenie nie powiedzie się, jeśli zostanie wychwycony wyjątek.Jeśli twój framework nie zapewnia tych środków, możesz to obejść, samodzielnie pakując wywołanie (piszę w C #):
To sprawia, że intencja jest bardziej wyraźna, ale do pewnego stopnia zaśmieca kod. (Oczywiście możesz zawinąć wszystkie te rzeczy w metodę). Na końcu to zależy od ciebie.
Edytować
Jak zauważył Doc Brown w komentarzach, problemem nie było wskazanie, że metoda rzuca, ale że nie rzuca. W NUnit jest na to również stwierdzenie
źródło
Wystarczy dodać komentarz, aby wyjaśnić, dlaczego nie jest potrzebne żadne potwierdzenie i dlaczego go nie zapomniałeś.
Jak widać w innych odpowiedziach, wszystko inne sprawia, że kod jest bardziej skomplikowany i zaśmiecony. Dzięki komentarzowi inni programiści znają zamiar testu.
Biorąc to pod uwagę, ten rodzaj testu powinien być wyjątkiem (nie ma zamiaru używać słów). Jeśli regularnie piszesz coś takiego, prawdopodobnie testy mówią ci, że projekt nie jest optymalny.
źródło
Można również stwierdzić, że niektóre metody są wywoływane (lub nie są wywoływane) poprawnie.
Na przykład:
W teście:
źródło