Jaka jest wartość sprawdzania w nieudanych testach jednostkowych?

13

Chociaż istnieją sposoby, aby nie przeprowadzać testów jednostkowych, jaka jest wartość sprawdzania w nieudanych testach jednostkowych?

Posłużę się prostym przykładem: rozróżnianie wielkości liter. W obecnym kodzie rozróżniana jest wielkość liter. Prawidłowym wejściem do metody jest „Cat” i zwraca ona wyliczenie Animal.Cat. Jednak pożądana funkcjonalność metody nie powinna uwzględniać wielkości liter. Więc jeśli opisana metoda zostanie przekazana jako „cat”, może zwrócić coś takiego jak Animal.Null zamiast Animal.Cat, a test jednostkowy zakończy się niepowodzeniem. Chociaż prosta zmiana kodu sprawiłaby, że to zadziałałoby, bardziej skomplikowany problem może zająć tygodnie, ale identyfikacja błędu za pomocą testu jednostkowego może być mniej złożonym zadaniem.

Aktualnie analizowana aplikacja ma 4 lata kodu, który „działa”. Jednak ostatnie dyskusje dotyczące testów jednostkowych wykazały wady w kodzie. Niektórzy potrzebują tylko jawnej dokumentacji implementacyjnej (np. Rozróżnia małe lub duże litery) lub kodu, który nie wykonuje błędu w oparciu o to, jak jest aktualnie wywoływany. Ale testy jednostkowe można tworzyć, wykonując określone scenariusze, które spowodują wyświetlenie błędu i będą prawidłowymi danymi wejściowymi.

Jaka jest wartość sprawdzania w testach jednostkowych, które wykonują błąd, dopóki ktoś nie będzie w stanie naprawić kodu?

Czy ten test jednostkowy powinien być oznaczony ignorowaniem, priorytetem, kategorią itp., Aby ustalić, czy kompilacja zakończyła się powodzeniem na podstawie wykonanych testów? Ostatecznie należy utworzyć test jednostkowy, aby wykonać kod, gdy ktoś go naprawi.

Z jednej strony pokazuje, że zidentyfikowane błędy nie zostały naprawione. Z drugiej strony, w dziennikach mogą pojawić się setki nieudanych testów jednostkowych, a przeglądanie tych, które powinny zakończyć się niepowodzeniem, a awarie spowodowane przez sprawdzenie kodu byłyby trudne do znalezienia.

Jim G.
źródło
To jeden ze sposobów na zwiększenie tych numerów pokrycia testowego.
JeffO
Jeśli włożyłeś już wysiłek w napisanie testu jednostkowego, dlaczego miałbyś chcieć go przepisać, gdy zdecydujesz się rozwiązać problem? Tylko dlatego, że jest zalogowany, nie oznacza, że ​​należy go uruchomić w pakiecie. (Możesz utworzyć kategorię „Znane problemy” i potraktować te testy jako listę zaległości / listy rzeczy do zrobienia.)
Caleb

Odpowiedzi:

17

Nie lubię zepsutych, niezatwierdzonych gości, ponieważ wytwarzają niepotrzebny hałas. Po każdym najcudowniejszym musiałbym sprawdzić wszystkie nieudane problemy (czerwony). Czy jest czerwony, ponieważ wystąpił nowy problem lub dlatego, że istnieje stara czynność do wykonania / naprawienia? Nie jest to w porządku, jeśli jest więcej niż 20 unittestów.

Zamiast tego używam

  • [Ignore("Reason")]atrybut, który powoduje, że wynik jest żółty lub
  • throw new NotImplementedException()dzięki temu wynik jest szary

Uwaga: używam NUnit dla .net. Nie jestem pewien, czy funkcja „szara” jest dostępna w innych najbardziej niestabilnych ramach.

Lubię więc następujące znaczenie wyników testów jednostkowych.

  • zielony: wszystkie gotowe
  • szary: planowane nowe funkcje, które należy wykonać, ale z niskim priorytetem
  • żółty: błędy jeszcze nie naprawione. Powinien zostać naprawiony wkrótce
  • czerwony: nowe błędy. Należy natychmiast naprawić

Wszystko oprócz „czerwonego” można zarejestrować.

Aby odpowiedzieć na pytanie: w „czerwonych-nieudanych testach” jest więcej szkody niż wartości, ale sprawdzanie w „testach zignorowanych na żółto” lub „testach niepoprawnych na szaro” może być przydatne jako lista rzeczy do zrobienia.

k3b
źródło
Problem, jaki widzę w tym podejściu, polega na tym, że zignorowane testy prawdopodobnie nigdy nie zostaną naprawione. Możesz też po prostu usunąć cały kod testowy, jaka byłaby różnica (jestem tu trochę zarozumiały)
Lovis
4
will probably never be fixedjest decyzją polityczną, jeśli chcesz wydać pieniądze na automatyczne testy, czy nie. Dzięki „ignorowanym testom” masz szansę je naprawić. Wyrzucanie „ignorowanych testów” oznacza „porzucać automatyczne testy do czasu, aż ich nie będzie”
k3b
8

Nie będę udawać, że jest to standard branżowy, ale sprawdzam zepsute testy, aby przypomnieć mi lub innym członkom mojego projektu, że nadal występuje problem z kodem lub samym testem jednostkowym.

Przypuszczam, że jedną rzeczą do rozważenia jest to, czy twoje zasady programistyczne pozwalają na nieudane testy bez kary. Mam przyjaciela, który pracuje w sklepie, który zajmuje się testowaniem, więc zawsze zaczynają od nieudanych testów ...

Tieson T.
źródło
5
Ale nigdy nie należy sprawdzać testu zakończonego niepowodzeniem, ponieważ serwer kompilacji nie powinien budować projektu z uszkodzonym testem.
CaffGeek
@Chad: Budowanie i testowanie to dwa osobne elementy jednego automatycznego kroku. Budowanie zapewnia, że ​​wszystko się kompiluje. Test zapewnia, że ​​wynik kompilacji jest poprawny. Moja interpretacja pytania brzmiała: „czy powinienem wpisać kod, który się nie kompiluje?” Zamiast tego brzmiało: „czy powinienem sprawdzić w teście, o którym wiem, że się nie uda?
Unholysampler
1
Właśnie dodałem punkt do rozważenia, niektóre serwery kompilacji z ciągłą integracją uruchamiają testy, a jeśli zawiodą, nie zostaną wdrożone. Słusznie, jak gdyby kompilacja zakończyła się niepowodzeniem, kod zawodzi i nie ma sensu wdrażać produktu, o którym wiadomo, że jest uszkodzony.
CaffGeek
@Chad: Racja, całkowicie zapomniałem o serwerach CI. To zdecydowanie byłby punkt do rozważenia. Warto również wyjaśnić, co rozumiemy przez „zepsute” testy; czy są to po prostu „złe” testy, czy test kończy się niepowodzeniem, ponieważ interfejs API zmienił się w jakiś sposób?
Tieson T.
Pytanie powinno być jaśniejsze. Powinien to być test, który się skompiluje, ale oczekiwany wynik nie powiedzie się.
6

Niepowodzenie testów jednostkowych daje zespołowi programistycznemu wgląd w to, co należy zrobić, aby spełnić uzgodnione specyfikacje.

Krótko mówiąc, nieudane testy jednostkowe dają zespołowi listę „DO ZROBIENIA”.

Z tego powodu nieudane testy jednostkowe są znacznie lepsze niż brak testów jednostkowych. *
Brak testów jednostkowych pozostawia zespół programistów w ciemności; specyfikacje muszą być wielokrotnie potwierdzane ręcznie .

[* Pod warunkiem, że testy jednostkowe faktycznie testują coś użytecznego.]

Jim G.
źródło
2
Istnieją lepsze sposoby prowadzenia listy rzeczy do zrobienia, np. Tablicy, aplikacji do zrobienia lub systemu śledzenia problemów. O wiele łatwiej jest korzystać z zestawu testów, jeśli oczekuje się, że zawsze przejdzie ono w pełni, a każda pojawiająca się awaria testu jest nowym problemem do natychmiastowego rozwiązania.
bdsl
6

Celem testów jednostkowych jest stwierdzenie oczekiwanego zachowania systemu, a nie dokumentowanie wad. Jeśli użyjemy testów jednostkowych do udokumentowania wad, ich przydatność do potwierdzenia oczekiwanego zachowania jest mniejsza. Odpowiedź na pytanie „Dlaczego test się nie powiódł?” nie jest proste: „Och, coś jest zepsute, czego się nie spodziewałem”. Nie wiadomo, czy błąd testu jest oczekiwany czy nieoczekiwany.

Oto akapit z początku rozdziału 13 efektywnej pracy ze starszym kodem :

Zautomatyzowane testy jednostkowe są bardzo ważnym narzędziem, ale nie do wykrywania błędów - przynajmniej nie bezpośrednio. Zasadniczo zautomatyzowane testy powinny określać cel, który chcielibyśmy osiągnąć, lub próbować zachować istniejące już zachowanie. W naturalnym przepływie rozwoju testy, które określają, stają się testami, które zachowują . Znajdziesz błędy, ale zwykle nie przy pierwszym uruchomieniu testu. Błędy znajdziesz w późniejszych uruchomieniach, gdy zmienisz zachowanie, którego się nie spodziewałeś.

Matthew Rodatus
źródło
3

Ale te zepsute, które identyfikują błędy w nowym projekcie, nazwanym jako takie. W ten sposób możesz zobaczyć, że POWINIEN się złamać ... Gdy zostaną naprawione, staną się zielone i zostaną przeniesione do normalnego zestawu testów.

UWAGA: Ten projekt musiałby zostać skonfigurowany tak, aby nie był budowany na serwerze kompilacji, jeśli serwer kompilacji zapobiega sprawdzeniom, które przerywają kompilację (zakładając, że zdefiniujesz zepsutą kompilację jako taką, w której wszystkie testy nie przejdą)

CaffGeek
źródło
+1, chociaż nie ma odpowiedzi, czy się zameldować, czy nie, jest ważny argument: build server
k3b
Wolę użyć atrybutu, aby oznaczyć taki test, zamiast przenieść go do osobnego projektu.
CodesInChaos
2

Testy jednostkowe powinny sprawdzać przypadki błędów oprócz przypadków powodzenia funkcji. Funkcja powinna wyraźnie odrzucać złe dane wejściowe lub powinna zawierać dokumentację wyjaśniającą, które dane wejściowe są uważane za prawidłowe.

Jeśli masz funkcję, która nie wykonuje żadnej z tych rzeczy, jest to błąd i powinieneś mieć sposób na zarejestrowanie, że ona istnieje. Jednym ze sposobów jest stworzenie testu jednostkowego wykazującego ten problem. Złożenie zgłoszenia błędu to kolejna opcja.

Celem testów jednostkowych nie jest osiągnięcie 100% sukcesu, chodzi o znalezienie i naprawienie błędów w kodzie. Nieprzeprowadzanie testów jest łatwym sposobem na osiągnięcie 100% sukcesu, ale nie jest to bardzo korzystne dla projektu.

unholysampler
źródło
Woah ... „Celem testów jednostkowych nie jest osiągnięcie 100% sukcesu”, mówisz, że nie wszyscy muszą zdać !?
CaffGeek 15.03.11
2
@Chad: Chodzi o to, że lepiej jest mieć testy, o których wiesz, że się nie powiodą, ale pokazują prawdziwy problem zamiast nie mieć testu tylko po to, abyś mógł mieć zielony znacznik wyboru na końcu nocnej kompilacji / testu.
unholysampler
8
@unholysampler, nigdy nie przełamuj testów, chyba że są WYRAŹNIE oznaczone jako „powinny” przerwać (będąc w innym projekcie). W przeciwnym razie stają się hałasem i nie wiadomo, kiedy test, który powinien przejść, został przerwany. Całkowicie pokonuje cel ciągłej integracji i przeprowadzania
testów jednostkowych
2
@Chad: Myślę, że przechodzi to w semantykę definicji. W oparciu o PO, brzmiało to tak, jakby mówił o stworzeniu ważnego testu, który wykonuje błąd. Jednak błąd ma niski priorytet i prawdopodobnie nie zostanie natychmiast naprawiony. To Ty wprowadziłeś Continuous Integration, która nakłada znacznie bardziej rygorystyczne ograniczenia na zautomatyzowany proces.
unholysampler
4
@unholysampler, CI lub brak CI, chodzi o to, że po uruchomieniu testów i przyzwyczajeni do niektórych czerwonych świateł, przyzwyczajasz się do tego. Więc kiedy coś, co było zielone, zmienia kolor na czerwony ... skąd wiesz?!? To okropna praktyka i jeden z powodów, dla których testowanie nie jest akceptowane w tak wielu organizacjach.
CaffGeek,
1

Zgłoś błąd dla każdej awarii i zwróć uwagę na wynik testu. Jeśli kiedykolwiek uda Ci się zebrać akt i naprawić błąd, test zostanie zaliczony i usuniesz go z wyniku testu. Nigdy nie ignoruj ​​problemów.

SnoopDougieDoug
źródło
-3

Jak widzę TDD wykonane przy implementacji testów dla niedokończonego kodu, najpierw napisz testy z atrybutem [ExpectedException] lub podobnym. Powinno to początkowo przejść, ponieważ niekompletny kod nie miałby żadnej logiki i zapisałby w nim nowy kod Exception (). Chociaż wyjątek przelotowy jest błędny, przynajmniej spowoduje to, że testy zakończą się pomyślnie i będą odpowiednie do sprawdzenia. Możemy zapomnieć o zignorowanym teście, ale zdecydowanie możemy uporządkować lub wypełnić niekompletny kod. Gdy to zrobimy, automatycznie odpowiedni test, który spodziewał się wyjątku, zacząłby się nie powieść i zaalarmowałby cię, aby go naprawić. Może to wymagać niewielkiej zmiany testu, aby pozbyć się ExpectException i zamiast tego wykonać prawdziwe twierdzenia. CI, deweloperzy, testerzy i klienci są szczęśliwi i wszyscy wygrywają?

użytkownik211764
źródło
1
To nie odpowiada na pytanie. Nie pyta, co to jest TDD i dlaczego testuje oczekiwane wyjątki.
Andy Wiesendanger