Modest Programmer logo
W poprzednim artykule na blogu wprowadziłem Cię do testów automatycznych. Jeżeli jeszcze go nie czytałeś, koniecznie zapoznaj się z nim, zanim przejdziesz do tego artykułu. Testy jednostkowe (unit tests), są właśnie jednym z typów testów automatycznych.


Czym są testy jednostkowe?


Zacznijmy od teorii. Testy jednostkowe są to małe kawałki kodu, które służą do testowania innego kodu, czyli pojedynczych jednostek, to znaczy klas i metod.

Testy Automatyczne Wyjaśnione w Jednym Artykule

Jakie powinny być testy jednostkowe?


#1 Powinny być wykonywane w izolacji bez zewnętrznych zależności.
Testy jednostkowe wykonywane są w izolacji bez jakichkolwiek zewnętrznych zależności takich jak plik, baza danych, czy webserwis. Testy, które korzystają z tych zależności to testy integracyjne, które bardziej szczegółowo opiszę w przyszłych artykułach na blogu. Testy integracyjne często przez programistów, są nazywane testami jednostkowymi, jednak testy jednostkowe i integracyjne to nie to samo.

#2 Testy jednostkowe powinny być powtarzalne i niezawodne.
Testy jednostkowe dzięki temu, że nie są uzależnione od żadnych zewnętrznych zależności, zawsze powinny być powtarzalne. Czyli wynik testu zawsze powinien być taki sam. Nie ma znaczenia, kiedy uruchomimy test jednostkowy, rano czy wieczorem, na innym komputerze, rok po napisaniu, czy uruchamiany jeden test jednostkowy, czy wszystkie naraz - wynik zawsze powinien być taki sam.

#3 Testy jednostkowe powinny być szybkie.
Testy jednostkowe są uruchamiane wiele razy, właśnie ze względu na to, że są szybkie. Jeżeli Twój test wykonuje się długo, to oznacza, że prawdopodobnie korzysta z jakichś zewnętrznych zależności i nie jest testem jednostkowym.

#4 Testy jednostkowe powinny być łatwe, czytelne, jeżeli się nie powiodą, to błąd powinien być łatwy do znalezienia.
Dla testów jednostkowych powinieneś stosować odpowiednie nazewnictwo, zgodne z konwencją. Twoje testy nie powinny zawierać zbyt dużo linii kodu i trzymać się zasady AAA (Arange, Act, Assert). Jeżeli test się nie powiedzie, powinien zwrócić właściwy komunikat, mówiący o tym, co poszło nie tak.

#5 Jest napisany z użyciem frameworka do testów jednostkowych.
Jest wiele frameworków, które możesz używać. Ja proponuję wybrać jeden z dwóch: NUnit lub xUnit.net. Dzisiejsze przykłady będę przedstawiał właśnie w NUnit, chociaż xUnit.net jest równie dobry. Jedyne co odradzam, to korzystanie z frameworka MSTest, co prawda jest on dostępny bez dodawania dodatkowych frameworków, ale jest trochę ograniczony, to znaczy brakuje mu niektórych ciekawych funkcji, które są w dwóch wcześniej wspomnianych.


Pierwszy test jednostkowy w C#


Napiszmy pierwszy kod jednostkowy w C# przy użyciu NUnit. Zaczniemy od prostego przykładu, spróbujemy napisać jeden test dla metody Add w klasie Calculator. Przykładowy kod tej metody może wyglądać w ten sposób:

public class Calculator
{
    public int Add(int number1, int number2)
    {
        return number1 - number2; //celowy błąd
    }
}

#1 Dodajemy nowy projekt z testami.
Najpierw należy dodać nowy projekt do naszej solucji. Zgodnie z konwencją może to być projekt o nazwie Calculations.UnitTests. W tym projekcie będą nasze testy jednostkowe. Najlepiej testy jednostkowe oddzielić od kodu produkcyjnego i testów integracyjnych.

#2 Do projektu z testami dodajemy referencję do projektu testowanego.
Można to zrobić na kilka sposobów. Na przykład klikając prawym przyciskiem na Calculations.UnitTests, następnie Add oraz Reference. Po otwarciu nowego okna z zakładki Project/Solution wybieramy projekt testowany, czyli w naszym przypadku Calculations.

#3 Instalujemy NUnit.
Przechodzimy do Manage NuGet Package i instalujemy dla projektu z testami NUnit.

#4 Dodajemy nową klasę odpowiadającą klasie testowanej.
W projekcie z testami dodajemy nową klasę, która będzie odpowiedzialna za testowanie klasy Calculator. Zgodnie z konwencją nazywamy ją CalculatorTests. W tej klasie będą dodawane metody testujące klasę Calculator. Dla każdej kolejnej klasy testowanej zawsze najlepiej dodać osobną klasę testującą, dzięki temu nasz kod staje się bardziej przejrzysty.

#5 Dodajemy pierwszą metodę testową.
Załóżmy, że na początek chcemy przetestować tak zwaną szczęśliwą ścieżkę (happy path), czyli testujemy metodę dla liczb, które powinny zachować się prawidłowo. Taka metoda może wyglądać mniej więcej tak:

public class CalculatorTests
{            
    [Test]
    public void Add_WhenCalled_ShouldReturnSum()
    {
        //Arrange
        var calculator = new Calculator();

        //Act
        var result = calculator.Add(1, 2);

        //Assert
        Assert.AreEqual(3, result);
    }
}

Nazywamy metodę według konwencji nazewniczej MetodaTestowana_Scenariusz_OczekiwaneZachowanie. Testujemy metodę Add, dla dwóch liczb i oczekujemy poprawnego wyniku, czyli sumy tych liczb. Aby metoda była testem, musi zostać oznaczona atrybutem [Test]. Często programiści oznaczają również klasę atrybutem [TestFixture], wynika to z tego, że w starszych wersjach NUnit było to wymagane, ale obecnie od wersji 2.5 nie jest to potrzebne. Następnie w ciele metody dzielimy nasz kod na trzy części: AAA, czyli Arrange, Act, Assert. W arrange jest tak zwane przygotowanie, czyli najczęściej są tutaj inicjalizowane obiekty, w naszym przykładzie tworzymy obiekt calculator. W act jest działanie, czyli wykonujemy metodę, którą chcemy testować, wywołujemy metodę Add z odpowiednimi parametrami. W assert sprawdzamy, czy wynik oczekiwany jest równy faktycznemu wynikowi. Klasa Assert jest z frameworka NUnit i zawiera jeszcze dużo więcej innych metod statycznych do weryfikowania wyników naszych testów. Taki podział metod jest często stosowany, dzięki niemu metoda testowa staje się przejrzysta. Oczywiście komentarze nie są tutaj potrzebne, można je usunąć, zostawiłem je tylko dla przejrzystości tego przykładu.

#6 Instalujemy NUnit3TestAdapter.
Jeżeli nie posiadamy ReSharpera, to aby można było uruchomić testy, musimy zainstalować poprzez Manage NuGet Package jeszcze jeden składnik - NUnit3TestAdapter.

#7 Uruchomienie testu.
Testy można uruchamiać na różne sposoby. Jeżeli używasz w visual studio to na początek w zakładce View kliknij w Test Explorer, dzięki temu pojawi Ci się okno z testami. Następnie widzisz strukturę Twoich testów, możesz uruchomić jeden test, możesz też uruchamiać wszystkie. Wystarczy kliknąć prawym przyciskiem myszy na nazwę testu i kliknąć Run. Testy są odpalane często, więc najlepiej jak w przyszłości będziesz używał do tego skrótów klawiszowych. Możesz użyć domyślnego lub dodać swój własny. Jak widzisz w test explorer nasz test zaświecił się na czerwono, to oznacz błąd w metodzie Add. Po kliknięciu w metodę testującą w test explorer możesz zobaczyć wiadomość: "Expected: 3 But was: -1". Celowo zrobiłem błąd w naszym przykładzie, który udało nam się wykryć w teście. Poprawiamy kod metody Add w klasie Calculator.

public class Calculator
{
    public int Add(int number1, int number2)
    {
        return number1 + number2;
    }
}

Ponownie uruchamiany test i teraz test świeci się na zielono. Oznacza to, że test przeszedł pozytywnie.


PODSUMOWANIE


Przykład w artykule nie był zbyt skomplikowany, myślę jednak, że na początek warto od takiego zacząć, tak aby przejść przez cały proces. W naszym przykładzie sprawdziliśmy tylko jeden przypadek testowy, ale zazwyczaj jak testujemy, to musimy sprawdzić więcej ścieżek. Sprawdzamy wszystkie warunki testowe, jeżeli w metodzie są jakieś instrukcje warunkowe, to wtedy liczba przypadków testowych rośnie. W kolejnych artykułach o testach pokaże Ci bardziej skomplikowane testy jednostkowe oraz jak pozbyć się zewnętrznych zależności z kodu.

Poprzedni artykuł - Testy Automatyczne Wyjaśnione w Jednym Artykule.
Autor artykułu:
Kazimierz Szpin
Kazimierz Szpin
Programista C#/.NET. Głównie pisze aplikacje w ASP.NET MVC, WPF oraz Windows Forms.
Autor bloga ModestProgrammer.pl
Dodaj komentarz
© Copyright 2020 modestprogrammer.pl. Wszelkie prawa zastrzeżone. Polityka prywatności. Design by Kazimierz Szpin