Jak zacząć pisać testy jednostkowe?

W aplikacji będącej aktualnie moim głównym zajęciem piszę testy jednostkowe. Dlatego postanowiłem, że co nieco o nich napiszę jako wstępniak do być może późniejszych wpisów na ten temat.

Co to są testy jednostkowe?

Testy jednostkowe to metody pisane w osobnym projekcie testujące pojedyncze elementy programu, czyli metody.

Po co pisać testy jednostkowe?

Testy piszemy po to, aby zapewnić kontrolę nad poprawnością wykonywanych przez program operacji. Bez testów ciężko jest to osiągnąć, ponieważ jeżeli w takiej sytuacji zmienimy, bądź zrefaktoryzujemy jakąś funkcję, musimy dużo czasu poświęcić na sprawdzenie, czy mimo zmiany na pewno funkcja wykonuje poprawnie oczekiwaną od niej operacje. Jeżeli mamy testy możemy je uruchomić w każdej chwili i sprawdzić w ciągu kilku sekund czy dla różnych danych wejściowych dana metoda zwraca poprawne wyniki.

Jakiego typu kod pokryć testami jednostkowymi?

Przede wszystkim taki kod, gdzie jest mnóstwo logiki do sprawdzenia, bo tam najłatwiej popełnić błąd. Musi też to być kod niezależny od żadnych zewnętrznych danych, czyli np. bazy danych lub systemu plików. Chcemy, aby wszystkie testy wykonywały się tylko w pamięci RAM.

Z czego składają się testy jednostkowe?

Testy jednostkowe składają się z trzech części:

Arrange

W tej części chcemy przygotować zmienne, obiekty, na których będziemy w późniejszym kroku używać metody. Są to też dane wejściowe do naszej funkcji.

Act

W tej części chcemy użyć metody, którą chcemy przetestować.

Assert

W tej części sprawdzamy, czy metoda zwróciła oczekiwany rezultat. To jest operacja, które będzie osądzać o poprawności wykonywania metody.

Jak napisać test jednostkowy w .NET Core?

Najpierw tworzymy klasę do przetestowania bez implementacji metod.

Tworzymy nowy projekt Class Library.

CreatingNewClassLibrary.png

CreatingNewClassLibrary2.png

Dodajemy zależności do projektu z klasą do przetestowania.

AddingReferenceToTheProject.png

AddingReferneceToTheProject2.png

Dodajemy paczki Nuget.

AddingNugets.png

AddingNugetsPackage.png

  • NUnit – framework do tworzenia testów jednostkowych.
  • NUnit3TestAdapter – framework umożliwiająca uruchamianie testów w Visual Studio.
  • Microsoft.NET.Test.Sdk – biblioteka umożliwiająca testowania aplikacji .NET Core.
  • FluentAssertions – ta pozycja nie jest konieczna, aczkolwiek jeżeli komuś zwykłe Asserty wydają się mało intuicyjne, warto ją dodać. Pozwala ona na pisanie assert’ów, tak żeby przypominały zdania w języku angielskim.

Tworzymy klasę do testowania, oznaczoną atrybutem [TestFixture].

Tworzymy metodę testującą, oznaczając ją atrybutem [Test]. Warto tu zwrócić uwagę, że nazwy metod nie są napisane notacją CamelCase, tylko wyrazy są poprzedzielane „_”. Podobno to zwiększa czytelność testów. Nie sprawdzałem, ale zakładam, że tak jest.

 

Piszemy testy jednostkowe.

 

W Visual Studio w zakładce Tests wchodzimy w Windows, a następnie Test Explorer lub klikamy Ctrl+E, T. Klikamy Run All. Jeżeli testy są poprawnie napisane, powinny zakończyć się niepowodzeniem.

Niedziałające testy jednostkowe.

Piszemy implementacje metod w projekcie produkcyjnym.

Teraz po uruchomieniu testów, jeżeli wszystko napisane jest poprawnie, powinny przejść.

Działające testy jednostkowe

Kolejnym krokiem powinna być refaktoryzacja kodu produkcyjnego. W tym przypadku chyba nie da się tego prościej napisać.

Całość kodu z powyższego poradnika znajduje się na GitHubie.

Podsumowanie

Warto pisać testy, ponieważ nie są one takie trudne, a potrafią oszczędzić długich sesji z debuggerem.

Jeżeli dotarliście do tego miejsca, to dziękuję za przeczytanie tego wpisu. Mam nadzieję, że przybliżył on wam temat testów jednostkowych. Jeżeli macie jakieś pytania albo sugestię piszcie w komentarzach poniżej. Do następnego wpisu, który już nie długo.

4 odpowiedzi do “Jak zacząć pisać testy jednostkowe?”

  1. Test pokrywający metodę Add (i inne) nie jest wystarczający, bo można go zazielenić taką implementacją:
    return -1;
    Polecam dodać więcej przypadków testowych 🙂

    1. Słusznie. Aczkolwiek te testy i tak są już oderwane od rzeczywistości, bo raczej nikt nie testuje prostych operacji matematycznych. Pozwoliłem sobie na pewne uproszczenie. Mimo wszystko się zgadzam i dziękuję za komentarz 🙂

  2. Kilka zastrzeżeń pomimo tak prostego przykładu:
    1. Odradzałbym wykorzystywanie „should” w nazwach testów. Masz to w każdym teście (strata miejsca na ekranie). Poza tym test nie sprawdza co kod powinien robić, ale co robi. Jak nie przechodzi tzn., że tego nie robi, a nie, że nie powinien tego robić 🙂 To jakby testy wymagań, a nie testy kodu.
    2. Wykorzystanie nazwy metody w nazwie testu jest sporym problemem jak zmieniasz nazwę metody. Jedyne co ci pozostaje to pamiętanie o tym, żeby zrobić Find and Replace. Dlatego nie wykorzystuję nazwy metody w testach. W twoim przypadku miałbym testy nazywające się np. tak: Adds_two_numbers, Subtracts_two_numbers…
    3. Jeżeli potrzebujesz komentarzy Arrange, Act, Assert tzn., że masz nieczytelne testy. Poszczególne bloki powinny być widoczne gołym okiem. Wystarczy wolny wiersz.
    4. Już wyżej wspomniane. Po napisaniu testu pisze się najprostszą implementację spełniającą wymagania. Gdy masz po jednym przypadku testowym jest to zwrócenie stałej. Dodajemy kolejny przypadek testowy i modyfikujemy kod. W tym przypadku to wydaje się bez sensu, ale gdy masz do zaimplementowania bardziej skomplikowany algorytm warto tak postępować.

    1. Wielkie dzięki za rady. Co do 3 punktu zwykle nie robię komentarzy. Tutaj sobie pozwoliłem w celach dydaktycznych. Być może nie potrzebnie. Mimo wszystko dzięki za komentarz 🙂

Możliwość komentowania jest wyłączona.