Jak piszesz przypadki testów jednostkowych?


14

Czasami kończę pisanie przypadków testowych dla kodu napisanego przez innych programistów. Są sytuacje, kiedy naprawdę nie wiem, co programista próbuje zrobić (część biznesowa) i po prostu manipuluję przypadkiem testowym, aby uzyskać zieloną linię. Czy te rzeczy są normalne w branży?

Jaki jest normalny trend? Czy programiści powinni pisać jednostkowe przypadki testowe dla napisanego przez siebie kodu?


2
"wgięcie"? Co znaczy „dint”?
S.Lott,

Odpowiedzi:


12

Spróbuj przeczytać ten post na blogu: Pisanie świetnych testów jednostkowych: najlepsze i najgorsze praktyki .

Ale w sieci jest niezliczona liczba innych.

W bezpośredniej odpowiedzi na twoje pytania ...

  1. „Normalny trend” - myślę, że może się to różnić w zależności od miejsca, co normalne dla mnie może być dziwne dla innych.
  2. Powiedziałbym (w mojej opcji), że programista, który pisze kod, powinien napisać test, najlepiej używając metod takich jak TDD, w których test byłby napisany przed kodem. Ale inni mogą mieć tutaj różne metody i pomysły!

A sposób, w jaki opisałeś pisanie testów (w swoim pytaniu) jest całkowicie błędny !!


9

Takie podejście czyni test jednostkowy bezwartościowym.

Test jednostkowy musi zakończyć się niepowodzeniem, gdy niektóre rzeczywiste działania nie działają zgodnie z przeznaczeniem. Jeśli nie zrobisz tego w ten sposób, a być może nawet napiszesz test przed testem kodu, to tak, jakbyś miał niedziałające czujniki dymu.


8
To nie do końca prawda. A raczej jest to prawda w idealnym świecie, ale niestety, często jesteśmy daleko od tego. Zastanów się nad posiadaniem starszego kodu bez testów i specyfikacji oraz bez nikogo, kto mógłby rzetelnie powiedzieć Ci najdrobniejsze szczegóły, co konkretnie powinien zrobić konkretny fragment kodu ( jest to rzeczywistość w dużej części istniejących projektów). Nawet w tym przypadku nadal warto pisać testy jednostkowe, aby zablokować bieżący stan kodu i upewnić się, że nic nie zepsujesz przy przyszłym refaktoryzacji, poprawkach lub rozszerzeniach.
Péter Török,

2
Myślę też, że miałeś na myśli „napisać test po kodzie do przetestowania”, prawda?
Péter Török

@ Péter, sformułowanie poszło nie tak - masz rację. Ale jeśli zdecydujesz się napisać testy, powinni zrobić coś , co będzie przydatne. Ślepo powołując kod mówiąc jest to badanie, jest - moim zdaniem - nie testuje.

Jeśli masz na myśli, że w naszych testach jednostkowych musimy mieć sensowne twierdzenia, aby sprawdzić, czy testowany kod rzeczywiście robi to, co naszym zdaniem robi, w pełni się zgadzam.
Péter Török

3

Jeśli nie wiesz, co robi funkcja, nie możesz napisać dla niej testu jednostkowego. Z tego co wiesz, nie robi nawet tego, co powinien. Najpierw musisz dowiedzieć się, co ma zrobić. NASTĘPNIE napisz test.


3

W świecie rzeczywistym pisanie testów jednostkowych dla kodu innej osoby jest całkowicie normalne. Jasne, pierwotny programista powinien już to zrobić, ale często otrzymujesz starszy kod, gdy tego po prostu nie zrobiono. Nawiasem mówiąc, nie ma znaczenia, czy ten starszy kod przyszedł kilkadziesiąt lat temu z odległej galaktyki, czy też jeden z twoich współpracowników sprawdził go w zeszłym tygodniu, czy też napisałeś go dzisiaj, starszy kod to kod bez testów

Zadaj sobie pytanie: dlaczego piszemy testy jednostkowe? Going Green jest oczywiście tylko środkiem do celu, ostatecznym celem jest udowodnienie lub obalenie twierdzeń dotyczących testowanego kodu.

Załóżmy, że masz metodę obliczającą pierwiastek kwadratowy z liczby zmiennoprzecinkowej. W Javie interfejs zdefiniowałby to jako:

public double squareRoot(double number);

Nie ma znaczenia, czy napisałeś implementację, czy też zrobił to ktoś inny, chcesz potwierdzić kilka właściwości squareRoot:

  1. że może zwrócić proste katalogi główne, takie jak sqrt (4.0)
  2. że może znaleźć prawdziwy root, jak sqrt (2.0) z rozsądną precyzją
  3. że stwierdzi, że sqrt (0,0) wynosi 0,0
  4. zgłasza IllegalArgumentException po podaniu liczby ujemnej, tj. na sqrt (-1.0)

Więc zacznij pisać jako indywidualne testy:

@Test
public void canFindSimpleRoot() {
  assertEquals(2, squareRoot(4), epsilon);
}

Ups, ten test już się nie powiedzie:

java.lang.AssertionError: Use assertEquals(expected, actual, delta) to compare floating-point numbers

Zapomniałeś o arytmetyki zmiennoprzecinkowej. OK, przedstaw się double epsilon=0.01i idź:

@Test
public void canFindSimpleRootToEpsilonPrecision() {
  assertEquals(2, squareRoot(4), epsilon);
}

i dodaj inne testy: w końcu

@Test
@ExpectedException(IllegalArgumentException.class)
public void throwsExceptionOnNegativeInput() {
  assertEquals(-1, squareRoot(-1), epsilon);
}

i jeszcze raz:

java.lang.AssertionError: expected:<-1.0> but was:<NaN>

Powinieneś był przetestować:

@Test
public void returnsNaNOnNegativeInput() {
  assertEquals(Double.NaN, squareRoot(-1), epsilon);
}

Co my tu zrobiliśmy? Zaczęliśmy od kilku założeń dotyczących tego, jak powinna zachowywać się metoda, i stwierdziliśmy, że nie wszystkie były prawdziwe. Następnie stworzyliśmy zestaw testowy Zielony, aby zapisać dowód, że metoda zachowuje się zgodnie z naszymi poprawionymi założeniami. Teraz klienci tego kodu mogą polegać na tym zachowaniu. Gdyby ktoś wymienił rzeczywistą implementację squareRoot na coś innego, coś, co na przykład naprawdę rzucił wyjątek zamiast zwracać NaN, nasze testy wychwyciłyby to natychmiast.

Ten przykład jest trywialny, ale często dziedziczysz duże fragmenty kodu, w których nie jest jasne, co właściwie robi. W takim przypadku normalne jest układanie uprzęży testowej wokół kodu. Zacznij od kilku podstawowych założeń dotyczących zachowania kodu, napisz dla nich testy jednostkowe, przetestuj. Jeśli zielony, dobrze, napisz więcej testów. Jeśli czerwony, to teraz masz nieudane stwierdzenie, które możesz trzymać przeciwko specyfikacji. Być może w starszym kodzie jest błąd. Być może specyfikacja nie jest jasna na temat tego konkretnego wejścia. Może nie masz specyfikacji. W takim przypadku przepisz test, aby udokumentował nieoczekiwane zachowanie:

@Test
public void throwsNoExceptionOnNegativeInput() {
  assertNotNull(squareRoot(-1)); // Shouldn't this fail?
}

Z czasem powstaje uprząż testowa, która dokumentuje rzeczywisty kod i staje się swoistą zakodowaną specyfikacją. Jeśli kiedykolwiek chcesz zmienić starszy kod lub zastąpić go innym, masz uprząż testową, aby sprawdzić, czy nowy kod zachowuje się tak samo lub czy nowy kod zachowuje się inaczej w oczekiwany i kontrolowany sposób (na przykład, że w rzeczywistości naprawia błąd, którego usunięcia się spodziewasz). Ta uprząż nie musi być kompletna pierwszego dnia, w rzeczywistości posiadanie niepełnej uprzęży jest prawie zawsze lepsze niż brak uprzęży. Posiadanie uprzęży oznacza, że ​​możesz łatwiej pisać kod klienta, wiesz, gdzie się spodziewać, że coś się zepsuje, gdy coś zmienisz, i gdzie się zepsuły, kiedy w końcu to zrobiły.

Powinieneś spróbować wyjść z myślenia, że ​​musisz pisać testy jednostkowe tylko dlatego, że musisz, tak jakbyś wypełniał obowiązkowe pola w formularzu. I nie powinieneś pisać testów jednostkowych, aby czerwona linia była zielona. Testy jednostkowe nie są twoimi wrogami, testy jednostkowe są twoimi przyjaciółmi.


1

Pisząc przypadki testowe (dla drukarek) staram się myśleć o każdym małym elemencie ... i co mogę zrobić, aby je zepsuć. Powiedzmy, na przykład, skaner, jakich komend używa (w języku pjl drukarka-zadanie-język), co mogę napisać, aby przetestować każdą funkcjonalność… Ok, teraz co mogę zrobić, aby to przerwać.

Staram się to robić dla każdego głównego komponentu, ale jeśli chodzi o oprogramowanie i nie tyle sprzętu, chcesz spojrzeć na każdą metodę / funkcję i sprawdzić granice i tym podobne.


1

Wygląda na to, że pracujesz z innymi programistami (lub utrzymujesz kod napisany przez innych programistów), którzy nie przeprowadzają testów jednostkowych. W takim przypadku myślę, że zdecydowanie chcesz wiedzieć, co powinien zrobić testowany obiekt lub metoda, a następnie utwórz dla niego test.

To nie będzie TDD, ponieważ najpierw nie napisałeś testu, ale możesz poprawić sytuację. Możesz także utworzyć kopię testowanych obiektów za pomocą kodów pośredniczących, aby ustalić, czy testy działają poprawnie w przypadku awarii kodu.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.