Testowanie - testy jednostkowe
Test jednostkowy (ang. unit test) to w programowaniu metoda testowania tworzonego oprogramowania poprzez wykonywanie testów weryfikujących poprawność działania pojedynczych elementów (jednostek) programu - np. metod lub obiektów w programowaniu obiektowym lub procedur w programowaniu proceduralnym. Testowany fragment programu poddawany jest testowi, który wykonuje go i porównuje wynik (np. zwrócone wartości, stan obiektu, wyrzucone wyjątki) z oczekiwanymi wynikami - tak pozytywnymi, jak i negatywnymi (niepowodzenie działania kodu w określonych sytuacjach również może podlegać testowaniu)
Test jednostkowy to fragment kodu, który sprawdza inny fragment kodu”
Więcej: Test jednostkowy
Aksjomaty testowania
- Żadnego realnego oprogramowanie nie da się przetestować całkowicie. Test nie udowadnia braku błędów, a udowadnia jedynie to, ze ich nie znaleźliśmy
- Testy są czasochłonne
- Testowanie jest kosztowne
- Testowanie jest ryzykowne
- Paradoks pestycydów
- Nie wszystkie znalezione błędy zostaną naprawione (za duży koszt, brak czasu, ryzyko naprawy)
- Testy są nużące
- Testowanie wymaga wyobraźni i złośliwości
Czym są testy jednostkowe?
Testy jednostkowe (ang. unit test) porównują oczekiwany wynik funkcji z rzeczywistym rezultatem. Na przykład sprawdźmy funkcję sumującą dwie liczby całkowite. W łatwy sposób można ustalić dane wejściowe oraz oczekiwany wynik:
Testy czarnej skrzynki.
Cechy
- pozwala efektywnie wyszukiwać błędy w istniejącym kodzie
- umożliwiają szybką weryfikację nowych elementów programu
- ułatwiają pracę zespołowądzięki łatwiejszemu łączeniu różnych fragmentów kodu podanych wcześniej testom
- zmusza do lepszego przemyślenia rozwiązań. Musimy dokładnie określić jakie zadania dana metoda ma wykonywać.
- oszczędność czasu - testy są w pełni powtarzalne i zautomatyzowane
- testy zautomatyzowane można uruchamiać regularnie o określonych porach lub na pewnych etapach produkcji (np. codziennie w nocy, aby rano był dostępny pełny raport)
- odporność na błędy regresyjne - błędy powracające po jakiejś modyfikacji kodu
Dobrze napisane testy
- Niezależność oraz izolacja
- sprecyzowany fragment kodu,
- nie można pisać testów badających kilka funkcji naraz,
- makiety obiektów,
- niezależność od zewnętrznych zasobów)
- Przejrzystość (testy mogą posłużyć jako dokumentacja)
- Szybkość
Test-driven development
Technika zwinna (agile), zaliczana także do programowania ekstremalnego.
- najpierw test sprawdzający dodawaną funkcjonalność (test nieudany)
- implementacja funkcjonalności (test udany)
- refaktoryzacja napisanego kodu, żeby spełniał on oczekiwane standardy.
Zalety:
- szybkie wychwytywanie błędów
- zmniejszenie kosztu, błędy wykryte przez autora kodu i poprawiane na bieżąco kosztują niewiele
- bardziej przemyślany kod
- możliwość przetestowania funkcjonalności bez uruchamiania całego oprogramowania
- tworzenie swoistej dokumentacji - test pokazuje jak używać danej funkcjonalności
Źródło: Test-driven development Wstęp do Test Driven Development (MSDN)
Środowiska testowe
Narzędzia i biblioteki wspierające tworzenie testów, ich organizację, automatyzację wykonywania, raportowanie
- Java → JUnit, TestNG
- PHP → PHPUnit
- C → MinUnit, CUnit, (biblioteka assert.h)
- c++ → Glib , Boost Test Library, CppUnit, Cantata++
- .Net → Visual Studio Unit Testing Framework (w VS od 2005, Proffesional, Ultimate), NUnit
- Delphi → DUnit, Fortran → pFUnit
List_of_unit_testing_frameworks
Testy jednostkowe w Visual Studio
- Tworzenie testu istniejącej metody:
- Create Unit test
- Wybieranie metod, dla których zostaną wygenerowane testy jednostkowe
- wygenerowany nowy projekt zawierający testy jednostkowe
- Automatycznie wygenerowana metoda testująca
- Uruchamianie testów → Run Tests
- Raport z wykonania testów
- Namespace: Microsoft.VisualStudio.TestTools.UnitTesting
- Assert
- ExpectedExceptionAttribute
- …
Przykład
public class BasicOperations { public int Add(int numberA, int numberB) { return numberA + numberB; } public int Subtract(int numberA, int numberB) { return numberA - numberB; } public int Multiply(int numberA, int numberB) { return numberA * numberB; } public int Divide(int numberA, int numberB) { return numberA / numberB; } }
Typy asercji
Zazwyczaj przyjmuje formę wyrażenia logicznego, które zwraca albo prawdę albo fałsz. Stanowi więc doskonałe narzędzie, dzięki któremu możemy w prosty sposób, wychwycić błędy w pisanych aplikacjach.
- AreEqual / AreNotEqual - czy równe / różne
- AreSame / AreNotSame - czy przekazane wartości nie odnoszą się do tego samego obiektu (bada referencje, a nie wartości)
- Fail - test jednostkowy jest niezaliczony
- Inconclusive -wykonanie testu jest nierozstrzygnięte
- IsTrue / IsFalse - czy dostarczona wartość lub wyrażenie są prawdziwe / fałszywe
- IsInstanceOfType / IsNotInstanceOfType - czy dostarczona wartość nie jest podanego typu
- IsNull / IsNotNull - czy dostarczona wartość nie jest NULL
Zakres dostępu
- metody publiczne, bez problemu
- metody chronione - nie można w bezpośredni sposób wywołać metody chronionej ze sterownika testu. Rozwiązaniem jest stworzenie klasy opakowującej dziedziczącej po badanej klasie i wywołanie chronionych metod w w dziedziczącej klasie bazowej
- metody prywatne są jeszcze trudniejsze do przetestowania. Nie nie można ich wywołać bezpośrednio w kodzie. Jednak modyfikatory public, protected, private mają znaczenie wyłącznie dla kompilatora. Za pomocą mechanizmu refleksji można ominąć ograniczenia i wywołać prywatną metodę.
Pokrycie kodu (code coverage)
Pokrycie kodu mierzy, ile procent kodu zostało sprawdzone przez testy jednostkowego. Przyjmuje się, że dobrze napisane testy powinny mieć pokrycie rzędu przynajmniej 70% . Wyróżniamy dwa sposoby wyliczania pokrycia:
- Pokrycie wyrażeń (ang. statement coverage) – metryka stanowi iloraz liczby linii kodu wywołanych przez testy jednostkowe oraz całkowitej liczby linii kodu. Jeśli jakaś linia nie została pokryta, istnieje zatem ryzyko wystąpienia w niej błędu.
- Pokrycie rozgałęzień (ang. branch coverage) – pokrycie nie bada linii kodu, a rozgałęzienia zrealizowane za pomocą np. instrukcji if.
- VS Test → Edit Test Settings → Local
- Data and Diagnostic → Code Coverag
- Configure - wybór źródła danych do analizy