Testuję, czy funkcja działa zgodnie z oczekiwaniami na liście. Więc chcę przetestować
f(null) -> null
f(empty) -> empty
f(list with one element) -> list with one element
f(list with 2+ elements) -> list with the same number of elements, doing what expected
Aby to zrobić, jakie jest najlepsze podejście?
- Testowanie wszystkich przypadków w tym samym teście (metodzie) pod nazwą „WorksAsExpected”
- Umieszczenie jednego testu dla każdego przypadku, a tym samym
- „WorksAsExpectedWhenNull”
- „WorksAsExpectedWhenEmpty”
- „WorksAsExpectedWhenSingleElement”
- „WorksAsExpectedWhenMoreElements”
- Kolejny wybór, o którym nie myślałem :-)
unit-testing
tdd
malarres
źródło
źródło
Odpowiedzi:
Prostą zasadą, której używam, aby wykonać zestaw testów w jednym przypadku testowym lub w wielu, jest: czy wymaga to tylko jednej konfiguracji?
Więc jeśli testowałem, że dla wielu elementów oba przetworzyły wszystkie z nich i uzyskały poprawny wynik, mogę mieć dwa lub więcej stwierdzeń, ale listę muszę skonfigurować tylko raz. Jeden przypadek testowy jest w porządku.
W twoim przypadku musiałbym jednak ustawić pustą listę, pustą listę itp. To wiele konfiguracji. Zdecydowanie stworzyłbym w tym przypadku wiele testów.
Jak wspomnieli inni, te „wielokrotne testy” mogą istnieć jako pojedynczy sparametryzowany przypadek testowy; tzn. ten sam przypadek testowy jest uruchamiany dla różnych danych konfiguracyjnych. Klucz do zrozumienia, czy jest to realne rozwiązanie, leży w innych częściach testu: „działaniu” i „zapewnieniu”. Jeśli możesz wykonać te same akcje i zapewnienia dla każdego zestawu danych, skorzystaj z tego podejścia. Jeśli zauważysz, że dodajesz
if
na przykład różne kody dla różnych części tych danych, nie jest to rozwiązanie. W tym drugim przypadku użyj indywidualnych przypadków testowych.źródło
Jest kompromis. Im więcej spakujesz w jednym teście, tym bardziej prawdopodobne będzie, że będziesz mieć efekt cebuli, próbując go przejść. Innymi słowy, pierwsza awaria kończy ten test. Nie poznasz innych twierdzeń, dopóki nie naprawisz pierwszej awarii. To powiedziawszy, posiadanie szeregu testów jednostkowych, które są w większości podobne, z wyjątkiem kodu konfiguracji, jest bardzo pracochłonne, aby dowiedzieć się, że niektóre prace są napisane, a inne nie.
Możliwe narzędzia, w zależności od twojego frameworka:
Assume.that()
prostu pomija test danych, jeśli nie spełni warunku wstępnego. Pozwala to zdefiniować „Działa zgodnie z oczekiwaniami”, a następnie po prostu podać mu dużo danych. Podczas przeglądania wyników masz pozycję dla testów nadrzędnych, a następnie pozycję dla każdego elementu danych.Nie jestem przekonany, że może być tylko jeden
assert
w teście stwierdzenie, ale stawiam ograniczenia, że wszyscy twierdzący powinni przetestować warunki pojedynczego działania. Jeśli jedyną różnicą między testami są dane, jestem skłonny do korzystania z bardziej zaawansowanych funkcji testowych opartych na danych, takich jak sparametryzowane testy lub teorie.Zważyć opcje, aby zdecydować, jaki jest najlepszy wynik. Powiem, że „WorksAsExpectedWhenNull” zasadniczo różni się od wszystkich przypadków, w których mamy do czynienia z kolekcją zawierającą różną liczbę elementów.
źródło
Są to różne przypadki testowe, ale kod testu jest taki sam. Dlatego stosowanie sparametryzowanych testów jest najlepszym rozwiązaniem. Jeśli środowisko testowe nie obsługuje parametryzacji, wyodrębnij udostępniony kod do funkcji pomocniczej i wywołaj go z poszczególnych przypadków testowych.
Staraj się unikać parametryzacji za pomocą pętli w jednym przypadku testowym, ponieważ utrudnia to określenie, który zestaw danych spowodował błąd.
W cyklu refaktora TDD czerwony – zielony – powinieneś dodawać jeden przykładowy zestaw danych na raz. Łączenie wielu przypadków testowych w sparametryzowany test byłoby częścią etapu refaktoryzacji.
Raczej odmienne podejście to testowanie nieruchomości . Utworzyłbyś różne (sparametryzowane) testy, które potwierdzą różne właściwości twojej funkcji, bez określania konkretnych danych wejściowych. Np. Właściwością może być: dla wszystkich list
xs
listays = f(xs)
ma taką samą długość jakxs
. Ramy testowe wygenerowałyby wówczas interesujące listy i listy losowe oraz zapewniłyby, że twoje właściwości zachowują je wszystkie. Odchodzi to od ręcznego określania przykładów, ponieważ ręczne wybieranie przykładów może pomijać interesujące przypadki krawędzi.źródło
Posiadanie jednego testu dla każdego przypadku jest właściwe, ponieważ testowanie pojedynczej koncepcji w każdym teście jest dobrą wskazówką, która jest często zalecana.
Zobacz ten post: Czy można mieć wiele twierdzeń w teście pojedynczej jednostki? . Jest tam również istotna i szczegółowa dyskusja:
[...]
źródło
Moim zdaniem zależy to od warunków testu.
źródło