Mam metodę, dla której chcę pisać testy jednostkowe. Zamierzam zachować to dość ogólne, ponieważ nie chcę omawiać implementacji metody, tylko jej testowanie. Metoda jest następująca:
public void HandleItem(item a)
{
CreateNewItem();
UpdateStatusOnPreviousItem();
SetNextRunDate();
}
Więc ta klasa ma jedną metodę publiczną, która następnie wywołuje niektóre prywatne metody do wykonania logiki.
Pisząc test jednostkowy, chcę sprawdzić, czy wszystkie trzy rzeczy zostały wykonane. Ponieważ wszystkie są wywoływane w tym samym przebiegu, pomyślałem, że mogę to zrobić jako jeden test:
public void GivenItem_WhenRun_Thenxxxxx
{
HandleItem(item);
// Assert item has been created
// Assert status has been set on the previous item
// Assert run date has been set
}
Ale pomyślałem, że mógłbym to również napisać jako trzy osobne testy:
public void GivenItem_WhenRun_ThenItemIsCreated()
{
HandleItem(item);
}
public void GivenItem_WhenRun_ThenStatusIsUpdatedOnPreviousItem()
{
HandleItem(item);
}
public void GivenItem_WhenRun_ThenRunDateIsSet()
{
HandleItem(item);
}
Wydaje mi się więc, że jest to ładniejsze, ponieważ zasadniczo wymienia wymagania, ale wszystkie trzy są ze sobą powiązane i wymagają dokładnie takiej samej pracy, jaką wykonano na testowanej metodzie, więc uruchamiam ten sam kod 3 razy.
Czy istnieje zalecane podejście do tego?
Dzięki
źródło
Krótka odpowiedź: o wiele ważniejsze jest, aby twoje testy obejmowały wszystkie funkcje, niż to, jak to robią.
Dłuższa odpowiedź: jeśli nadal chcesz wybierać spośród tych w dużej mierze równoważnych rozwiązań, możesz zastosować kryteria pomocnicze dla tego, co najlepsze. Na przykład,
źródło
Użyj jednego wywołania metody z wieloma potwierdzeniami. Dlatego:
Podczas testowania HandleItem (a) testujesz, czy metoda doprowadziła element do właściwego stanu. Zamiast „jednego potwierdzenia na test” pomyśl „jedna logiczna koncepcja na test”.
Pytanie: Jeśli CreateNewItem się nie powiedzie, ale pozostałe dwie metody się powiodły, czy to oznacza, że HandleItem zakończyło się pomyślnie? Chyba nie.
Dzięki wielu twierdzeniom (z odpowiednimi wiadomościami) będziesz dokładnie wiedział, co się nie udało. Zazwyczaj metoda jest testowana wiele razy dla wielu danych wejściowych lub stanów wejściowych, aby uniknąć wielu twierdzeń.
IMO, te pytania są zazwyczaj oznaką czegoś innego. To znak, że HandleItem nie jest tak naprawdę czymś, co można „testować jednostkowo”, ponieważ wydaje się, że po prostu deleguje na inne metody. Gdy po prostu sprawdzasz, czy HandleItem poprawnie wywołuje inne metody, staje się bardziej kandydatem do testu integracji (w takim przypadku nadal będziesz mieć 3 potwierdzenia).
Możesz rozważyć upublicznienie pozostałych 3 metod i przetestowanie ich niezależnie. Lub nawet wyodrębnić je do innej klasy.
źródło
Użyj drugiego podejścia. Przy pierwszym podejściu, jeśli test się nie powiedzie, od razu nie dowiesz się, dlaczego, ponieważ może to być jedna z 3 funkcji, które zawiodły. Przy drugim podejściu od razu dowiesz się, gdzie wystąpił problem. Możesz umieścić zduplikowany kod w funkcji Test Setup.
źródło
IMHO powinieneś przetestować trzy części tej metody osobno, abyś dokładniej wiedział, gdzie coś idzie nie tak, unikając dwukrotnego przejrzenia tej samej części kodu.
źródło
Nie sądzę, aby istniała mocna potrzeba do napisania osobnych metod testowania dla twojego przypadku użycia. Jeśli chcesz uzyskać wyniki ze wszystkich trzech zmiennych, możesz przetestować wszystkie trzy i wydrukować ich awarie, łącząc je w
string
ai stwierdzając, czy łańcuch jest nadal pusty po zakończeniu testu. Utrzymując je wszystkie w tej samej metodzie, twoje warunki i komunikaty o błędach dokumentują oczekiwany stan końcowy metody w jednym miejscu, zamiast dzielić ją na trzy metody, które mogą później zostać rozdzielone.Oznacza to, że twój pojedynczy test będzie zawierał więcej kodu, ale jeśli masz tak wiele post-warunków, że jest to problem, prawdopodobnie chcesz zreformować metody testowania, aby przetestować poszczególne metody wewnątrz
HandleItem
.źródło