Co to są testy jednostkowe?

Kiedy test przestaje być jednostkowy

Featured image

Zauważam pewną paranoję wśród początkujących deweloperów. Mają obsesję na temat testów jednostkowych, kiedy stosować, kiedy nie stosować, co to jest test jednostkowy. A czy kiedy zrobię w teście zapytanie do bazy danych to jeszcze jest test jednostkowy czy już nie? Dyskusję można na ten temat ciągnąć bez końca.

Zacznę od cytatu z Kenta Becka:

Being proud of 100% test coverage is like being proud of reading every word in the newspaper. Some are more important than others.

Tworzenie testów jednostkowych ma sens jedynie wtedy kiedy są one absolutnie niezbędne i łatwo jest je napisać. Wielokrotnie widziałem wpisy ludzi którzy, moim zdaniem, na siłę robili testy rzeczy albo nie nadających się do testowania albo nieistotnych. W prawdziwym świecie musisz bowiem zdać sobie jeszcze pytanie - kto za napisanie tych testów zapłaci i kto będzie płacił w przyszłości za ich utrzymanie. Dlatego nawalenie całego wiadra testów jednostkowych na siłę to błąd tu znowu cytat “The Best Code is No Code At All”.

W dużej firmie nikt nie będzie tracił czasu na pisanie testów jednostkowych tylko po to żeby mieć 100% pokrycia. Dlaczego? Dlatego że nikt nie da na to pieniędzy. No bo ile pieniędzy przniesie twojemu pracodawcy zwiększenie pokrycia z np. 30% do 100%? Pewnie 0.

Należy pamiętać że napisanie każdej liniki testu jednostkowego zwiększa rozmiar kodu do utrzymania. A utrzymanie kodu kosztuje. Na dodatek pisanie kiepskich (na siłę) testów dodaje kodu który trzeba utrzymywać. Nie daje żadnego zysku twojemu pracodawcy.

W praktyce często stosuje się metodę “fix by remove” do testów jednostkowych - dostajesz wielką bazę źle napisanych testów jednostkowych. Co robisz? Naprawiasz? Nie - usuwasz wszystko do kosza i wracasz do sprawy jak będzie ważny ku temu powód. Nie piszesz testów na siłę. A co najważniejsze - nie piszesz kodu na zapas. Pisanie kodu na zapas też ma w świecie programowania swoją nazwę: przedwczesna optymalizacja.

Testy jednostkowe jak nazwa wskazuje mają testować każdą jednostę twojego kodu niezależnie.

Należy także pamiętać o tym, że jeśli jakaś cześć twojego kodu X działa dobrze (przechodzi testy jednostkowe) oraz inna cześć twojego kodu Y działa dobrze (przechodzi testy jednostkowe) - wcale nie znaczy to że są one ze sobą kompatybilne i że wspólnie będą działać dobrze. To jest właśnie pułapka testów jednostkowych - ułuda bycia bezpiecznym. A tak naprawdę tylko dobrze przeprowadzone testy manualne zapewniają względne bezpieczeństwo. Dobrze czyli skrupulatnie, systematycznie, dokładnie i robione przez doświadczonych testerów manualnych.

Więc jeśli próbujesz znaleźć błędy w kodzie o wiele lepszym rozwiązaniem jest uruchomienie aplikacji i przekilkanie jej. Na kilkunastu urządzeniach. Na kilkadziesiąt różnych sposobów. Przez kilka różnych osób. W ciągu kilku dni (serwer jednego dnia mógł działać dobrze, a drugiego zgłaszał z jednego enpointa błąd).

Jedynym momentem kiedy testy jednostkowe znajdują “błędy” (ale nie dzieje się to podczas działania apki tylko w momencie jej dewelopowania/budowania bo właśnie wtedy zapuszcza się unit testy) to wtedy kiedy robisz refaktor kodu. Co to jest refaktor kodu - zmieniasz strukturę kodu (usuwasz / reorganizujesz metody prywatne, zmieniasz synchronizację wątków - ogólnie zmieniasz implementację jednostki kodu) - bez zmieniania interfejsu i zachowania.

Dlatgo właśnie testy jednostkowe i TDD w ogóle można przyjąć za proces projektowania kodu (tak aby był on testowalny) a nie proces testowania kodu. TDD wymusza tworzenie niezależnych od siebie jednostek kodu a napisane testy są jedynie dokumentacją: jak na wejściu będzie A to na wyjściu ma być X itd.

Jeśli natomiast twój test wygląda tak: na wejściu A a w środku B z konfiguracją C oraz D z fabryki E to na wyjściu Y - to znaczy że coś poszło nie tak.

Testu jednostkowe nie powinny zawierać żadnej dodatkowej wiedzy o innych jednostkach poza tą którą właśnie testujesz. Więc całe to “w środku B z konfiguracją C oraz D z fabryki E” w teście prawdziwie jednostkowym nie powinno mieć miejsca.

Na koniec kilka praktycznych wskazówek jak pisać testy jednostkowe: