Czy każdy test jednostkowy powinien być możliwy niezależnie od innych testów?

24

Załóżmy, że masz testy dla dwóch metod klasy. Pierwsza metoda zbiera dane z innej warstwy i umieszcza je w jakimś magazynie niezależnym od środowiska wykonawczego (takim jak tabela SQL), więc wszystkie dane obsługiwane przez ten test są zakodowane na stałe w teście. Druga metoda jest odpowiedzialna za pobieranie danych z miejsca, w którym opuściła je pierwsza metoda i przekształcanie jej w jakiś sposób (obliczenia, przenoszenie niektórych części w inne miejsca itp.).

Teraz ta druga metoda może mieć zakodowane dane wejściowe, takie jak pierwsza, lub można założyć, że dwa testy zostaną uruchomione sekwencyjnie i może zacząć od miejsca, w którym zakończył się pierwszy test, biorąc dane, które były naprawdę zapisane w pierwszym teście.

Jeśli wybrałeś drugą opcję, naprawdę miałbyś dobry pomysł, że obie metody dobrze się ze sobą bawią, jednak jeśli pierwszy test się nie powiedzie, wszystkie testy po nim się nie powiodą, pozbawiając korzyści z testowania, pomagając szybciej izolować błędy.

Jeśli wybrałeś pierwszą opcję, każda metoda byłaby izolowana i testowana niezależnie, ale tak naprawdę nigdy nie wiedziałbyś, że naprawdę mogą ze sobą poprawnie współpracować.

Która jest tutaj lepsza opcja? Czy istnieje jakaś alternatywa, na przykład posiadanie jednego testu dla każdej izolowanej metody z kodowaniem na twardo, a następnie większych testów, które zawierają obie metody w jednym?

Morgan Herlocker
źródło
2
Naprawdę chciałbym móc z łatwością losować kolejność testów jednostkowych za każdym razem, gdy są uruchamiane. W tej chwili działają w nieznanym, aczkolwiek względnie ustalonym porządku.
Job

Odpowiedzi:

11

Jeśli wybrałeś pierwszą opcję, każda metoda byłaby izolowana i testowana niezależnie, ale tak naprawdę nigdy nie wiedziałbyś, że naprawdę mogą ze sobą poprawnie współpracować.

Jeśli twoje metody są naprawdę niezależne, nie powinno to mieć znaczenia. Twoja druga metoda powinna:

a) Działa poprawnie, jeśli jest przedstawiany z ważnymi danymi.

b) Zawodzą w sposób rozsądny i konsekwentny, gdy są przedstawiane z nieprawidłowymi danymi.

Podobnie twoja pierwsza metoda powinna zrobić to samo. Tak długo, jak zajmujesz się przypadkami błędów, będą one działały poprawnie.

Jeśli chcesz sprawdzić, czy metody działają poprawnie razem, to jest to test integracyjny, a nie test jednostkowy.

ChrisF
źródło
27

Jeśli testy nie mogą przebiegać niezależnie, to nie są to testy jednostkowe.

Test jednostkowy nie powinien opierać się na żadnym stanie zewnętrznym, takim jak zawartość tabeli bazy danych. Powinien on czysto przetestować jedną jednostkę kodu w izolacji.

Testy, które zmieniają lub wymagają określonego stanu, są ważne, mogą na przykład stanowić część testów integracyjnych, w takich przypadkach ważne jest, aby upewnić się, że dokonano odpowiedniej konfiguracji, ale nie byłyby to testy jednostkowe. W tym przypadku nadal nie radziłbym, aby jeden test wymagał uruchomienia innego. Jeśli tak jest, powinieneś prawdopodobnie rozdzielić wymagany kod na osobną metodę konfiguracji. Możesz mieć jeden test, który następnie wywołuje kod konfiguracji i weryfikuje na przykład, czy nie zgłoszono wyjątku, a następnie inny test, który aktywnie wykorzystuje dane ustawione w metodzie konfiguracji.

Steve
źródło
@ Steve, więc w tym przykładzie powiedziałbyś: jeden test dla metody 1, jeden test dla metody 2 i jeden test, który uruchamia 1 i 2 w tym samym teście?
Morgan Herlocker,
2
Tak. pierwsze dwa będą testami jednostkowymi, trzeci brzmi jak test integracyjny.
Steve
jeśli masz moduł klienta i moduł zamówień i zamówienia nie można utworzyć bez relacji z klientem. Jak przetestujesz go niezależnie od modułu klienta: utwórz rekord klienta w bazie danych za pomocą sql (wstaw do klienta) lub użyj Customer.createCustomer (). IMHO używa drugiego, ponieważ jest lepszy, ponieważ nie potrzebujesz usprawnienia żadnej logiki w teście, ale działa to tylko wtedy, gdy test na tworzenie klientów przejdzie pomyślnie.
Dainius
@Dainius. W scenariuszu testu jednostkowego zwykle używasz fałszywych obiektów, więc przekazujesz fałszywego klienta do modułu zamówienia. Masz rację, ponieważ w tym przypadku nie chcesz używać sql.
Steve
wydaje się, że w każdym scenariuszu, w którym metoda B zależy od metody A, prawie zawsze będzie metoda C, która wywołuje A, a następnie wywołuje B. Ponieważ tak jest, można przetestować A, B i C niezależnie.
Morgan Herlocker,
9

Jestem pewien, że teraz wydaje się OK, aby mieć test jednostkowy B, który zależy od stanu pozostawionego przez test jednostkowy B. Ale zastanów się za rok, kiedy masz tysiąc testów jednostkowych. Czy naprawdę chcesz poczekać dziesięć minut, aż cały zestaw testów zakończy się za każdym razem, gdy musisz wprowadzić zmiany?

Zależy to oczywiście od twojego stylu programowania, ale jeśli chcesz mieć nadzieję na przyzwoity rozwój oparty na testach, w którym możesz wiele razy przeprowadzić indywidualny test podczas opracowywania funkcji, sugeruję, aby dać każdemu testowi możliwość samodzielnego działania.

Steve Rukuts
źródło
1
+1 Raskolnikow, nie pomyślałem, że to będzie ogromny czas później, kiedy „przeprowadzę wszystkie testy” później.
Morgan Herlocker,
3

Wygląda na to, że mówisz o konfiguracji testowej, którą można wykonać na kilka sposobów. Chcesz czystą kopię danych testowych (zwaną urządzeniem) dla każdego testu, więc każdy z nich nie powinien zależeć od siebie.

Istnieje kilka frameworków, które pozwalają na tego typu testy, oraz narzędzia takie jak DBUnit, które pozwalają szybko budować i burzyć struktury danych na początku i na końcu testów oraz pakietów testowych.

TrueDub
źródło