2008-10-04 14 views
6

Będąc nowicjuszem w rozwoju testowym, to pytanie mnie dręczyło. Jak dużo jest za dużo? Co powinno być testowane, jak powinno być testowane i dlaczego powinno być testowane? Podane przykłady są w języku C# z NUnit, ale zakładam, że samo pytanie jest agnostyczne.Przypadki testowe "kiedy", "co" i "dlaczego"?

Oto dwa aktualne przykłady własne testy na ogólną listę obiektów (testowane z ciągami, funkcja inicjalizacji dodaje trzy elementy {"Foo", "Bar", "Baz"}):

[Test] 
public void CountChanging() 
{ 
    Assert.That(_list.Count, Is.EqualTo(3)); 
    _list.Add("Qux"); 
    Assert.That(_list.Count, Is.EqualTo(4)); 
    _list[7] = "Quuuux"; 
    Assert.That(_list.Count, Is.EqualTo(8)); 
    _list.Remove("Quuuux"); 
    Assert.That(_list.Count, Is.EqualTo(7)); 
} 

[Test] 
public void ContainsItem() 
{ 
    Assert.That(_list.Contains("Qux"), Is.EqualTo(false)); 
    _list.Add("Qux"); 
    Assert.That(_list.Contains("Qux"), Is.EqualTo(true)); 
    _list.Remove("Qux"); 
    Assert.That(_list.Contains("Qux"), Is.EqualTo(false)); 
} 

Kod jest dość self-komentowania, więc Nie będę się wdawał w to, co się dzieje, ale czy to nie jest zajęcie zbyt daleko? Add() i Remove() są testowane osobno oczywiście, więc na jaki poziom powinienem przejść z tego rodzaju testami? Czy powinienem mieć nawet tego rodzaju testy?

Odpowiedz

7

Powiedziałbym, że to, co faktycznie testujesz, to klasy równoważności.Moim zdaniem nie ma różnicy między dodaniem do listy zawierającej 3 przedmioty lub 7 przedmiotów. Istnieje jednak różnica między 0 pozycjami, 1 pozycją i> 1 pozycjami. Najprawdopodobniej będę miał 3 testy dla metod Add/Remove dla tych przypadków.

Po pojawieniu się błędów z QA/użytkowników, dodałem każdy taki raport o błędzie jako przypadek testowy; zobacz błąd rozmnażaj się przez uzyskanie czerwonego paska; napraw błąd, zdobywając zielony pasek. Każdy taki "wykrywanie błędów" pozostanie - to moja sieć bezpieczeństwa (czytaj: test regresji), że nawet jeśli popełnię ten błąd ponownie, będę miał natychmiastową informację zwrotną.

+0

Powodem, dla którego go przygotowałem (używając .Add()), było to, że większość metod, które muszą pracować z danymi testowymi, ma coś, z czym można pracować. –

+0

Rozumiem to. Jednak twoja lista może być pusta, co jest poprawnym stanem (tzn. Count powinien zwracać 0 itd.) Jest to zasadniczo "inne" niż dodanie do listy, która już zawiera elementy - stąd określenie "klasy równoważności". – Yuval

+0

Mam test dla .Clear() i test do dodawania po .Clear(), a także test do tworzenia i dodawania do listy, która została utworzona bez początkowej pojemności. Myślę, że nadal jestem objęta, chyba że możesz wymyślić coś innego? –

1

Czy _list jest instancją klasy, którą napisałeś? Jeśli tak, powiedziałbym, że testowanie jest uzasadnione. Jednak w takim przypadku, dlaczego tworzysz niestandardową klasę List?

Jeśli nie jest to kod, który napisałeś, nie testuj go, chyba że podejrzewasz, że jest w jakiś sposób błędny.


Próbuję przetestować kod, który jest niezależny i modułowy. Jeśli istnieje jakiś rodzaj funkcji Boga w kodzie, który muszę utrzymywać, rozszyfrowuję go jak najwięcej w podfunkcje i testuję je niezależnie. Wtedy funkcja Boga może być napisana jako "oczywiście poprawna" - bez gałęzi, bez logiki, po prostu przekazując wyniki z jednej dobrze przetestowanej podfunkcji do drugiej.

+0

To jest mój własny kod, a na piśmie testy faktycznie ujawniły błędy, mimo że nie podejrzewałam, że są błędne. Jeśli chodzi o powód, dla którego odkrywam koło, że tak powiem, potrzebowałem klasy typu List , która obsługuje zdarzenia, gdy elementy zostały dodane/usunięte itp. –

+0

Skoro to twój kod, to tak, pisz testy dla niego. Nawet jeśli pisanie ich jest nudne lub czuje się nieekonomiczne, każdy test na nietrywialną klasę może zapobiec godzinom frustracji na drodze. Jedyne testy, których nie piszę w języku C#, dotyczą właściwości {get; set;}. –

+0

Dlaczego po prostu nie napisać dekoratora dla domyślnej listy generycznej, która uruchamia te zdarzenia na add/remove, przekazując rzeczywistą pracę do nadklasy? – jdmichal

6

Pomyśl o swoich testach jako o specyfikacji. Jeśli Twój system może się zepsuć (lub mieć istotne błędy) bez niepowodzenia testów, oznacza to, że nie masz wystarczającego zasięgu testowego. Jeśli jeden punkt awarii powoduje, że wiele testów się zepsuje, prawdopodobnie masz za dużo (lub są zbyt ściśle powiązane).

To jest naprawdę trudne do zdefiniowania w obiektywny sposób. Przypuszczam, że powiedziałbym, że popełniłem błąd przy testowaniu zbyt wiele. Wtedy, gdy testy zaczynają was denerwować, są to konkretne testy do refaktoryzacji/zmiany przeznaczenia (ponieważ są zbyt kruche, albo testują niewłaściwą rzecz, a ich niepowodzenia nie są użyteczne).

2

Kilka porad:

  1. Każdy powinien przetestować testcase tylko jedno. Oznacza to, że struktura testówki powinna być "setup", "execute", "assert". W swoich przykładach mieszasz te fazy. Spróbuj podzielić swoje metody testowe. Dzięki temu łatwiej zobaczyć dokładnie, co testujesz.

  2. Spróbuj podać metodom testowym nazwę opisującą to, co testuje. To znaczy. trzy testcases zawarte w twoim ContainsItem() stają się: containsReportsFalseIfTheItemHasNotBeenAdded(), containsReportsTrueIfTheItemHasBeenAdded(), containsReportsFalseIfTheItemHasBeenAddedThenRemoved(). Uważam, że zmuszanie się do wymyślania opisowej nazwy pomaga mi wyobrazić sobie to, co muszę przetestować, zanim zakodowuję rzeczywisty test.

  3. Jeśli wykonujesz TDD, powinieneś napisać swój test jako pierwszy i dodać kod do swojej implementacji tylko wtedy, gdy masz awaryjny test. Nawet jeśli tego nie zrobisz, da ci to pojęcie, ile testów wystarczy. Możesz też użyć narzędzia do pokrycia. W przypadku prostej klasy, takiej jak kontener, powinieneś dążyć do 100% pokrycia.

+0

Przedtem nie robiłem TDD, jest to moja pierwsza próba, i zamieniam małą bibliotekę (około 6-8 klas) z innego projektu i piszę o testach jako wstęp. Rozumiem zalety pisania testu w pierwszej kolejności, ale w tym przypadku po prostu nie wiedziałem nic lepszego. –

+0

"zawieraReportsFalseIfTheItemHasBeenAddedThenRemoved" hoooooooly shit! Podczas pisania testów nie ma nic złego w "TestContains1", "TestContains2", itp. –

+1

Nic poza tym, że gdy test się nie powiedzie, nie masz pojęcia, co faktycznie zawiodło, nie patrząc na kod testowy. Wszystko po to, by raz zapisać kilka znaków i nigdy więcej nie zaglądać? – jdmichal

Powiązane problemy