fbpx

Kiedy testy jednostkowe są zbędne?

Created with Sketch.

Kiedy testy jednostkowe są zbędne?

Post-22

OHO. Zaczyna się. Kolejny pseudoprogramista chce się lansować na TDD is dead. Już to przerabialiśmy Wojtek, daj spokój.

Ja jednak będę nalegał. Chciałbym porozmawiać o konkretnym przykładzie, który jest bardzo jasnym zapaszkiem (bardziej nawet smrodem), że coś złego się dzieje z Twoimi testami jednostkowymi.

Dobry test, zły test…

Zacznijmy od klasyki – czym jest test jednostkowy? Będę posiłkował się opinią autorytetów w tej sprawie:

Unit testing is often talked about in software development, and is a term that I’ve been familiar with during my whole time writing programs. Like most software development terminology, however, it’s very ill-defined, and I see confusion can often occur when people think that it’s more tightly defined than it actually is.

[…]

Despite the variations, there are some common elements. Firstly there is a notion that unit tests are low-level, focusing on a small part of the software system. Secondly unit tests are usually written these days by the programmers themselves using their regular tools – the only difference being the use of some sort of unit testing framework. Thirdly unit tests are expected to be significantly faster than other kinds of tests.

Martin Fowler (bliki – UnitTest)

Podsumowując, test jednostkowy powinien:

  1. Testować minimalny fragment systemu.
  2. Być tworzony przez programistów z użyciem jakiegoś narzędzia.
  3. Ma dawać odpowiedź dużo szybciej niż inne rodzaje testów.

Nie odkryliśmy tutaj Ameryki. Przyznacie jednak, że ten zestaw wymagań mówi o tym, że testy jednostkowe należałoby potraktować elastyczniej, niż niektórzy proponują.

Co tu tak śmierdzi? Framework czy Twoje testy?

Wróćmy do tytułowego pytania, czy jesteście w stanie sobie wyobrazić sytuację, że testy jednostkowe są nie potrzebne? Tak, podam wam taki przykład, ale potrzebuję poczynić pewne założenia:

  1. Traktujemy TDD i definicję testu jednostkowego bardzo dosłownie, wręcz dogmatycznie (tak jak każe taki jeden wujo).
  2. Korzystamy, jak każdy dobry inżynier nie wynajdujący koło na nowo, z wszelakiej maści frameworków (a dajmy dla przykładu Spring Framework).
  3. Tworzymy nietrywialny, ale dość powtarzalny (w sensie wymaganej funkcjonalności np. nietypowe API do uwierzytelniania i autoryzacji) kawałek kodu z minimalną ilością logiki biznesowej.

Zgoda? Super, tylko poczekajcie, bo ja sobie pójdę zrobić popcorn.

W takim układzie wszyscy dogmatycy traktujący testy jednostkowe jak świętość, będą musieli mocno się napocić aby stworzyć siatkę bezpieczeństwa w oparciu o ten rodzaj testów, żeby to niosło jakąkolwiek wartość, oraz nie przypominało utrzymaniowego potwora Frankensteina, złożonego z mocków, Test Doubles, Stubów (albo raczej trola zlepionego z gliny, błota i g…mocków). Szach-Mat Ekstremiści!

Dlaczego tak się dzieje? Ano dlatego, że fizyki nie oszukasz i albo zaczynasz testować jednostkowo framework z którego korzystasz (bardzo głupi pomysł), albo wciskasz niesamowitą ilość złożoności przypadkowej do testów, żeby tego uniknąć (teraz w sumie nie wiem, który pomysł jest głupszy).

Inne podejście do sprawy

W takim podejściu najlepiej byłoby skierować swój wzrok w stronę testów integracyjnych, i oprzeć siatkę bezpieczeństwa o ten rodzaj testów.

Zaraz moment! Czy ty chcesz powiedzieć, że w tym przypadku nie potrzebujemy w ogóle testów jednostkowych?

Nie. Moim skromnym zdaniem mamy tutaj problem z nazewnictwem i dogmatycznym przywiązaniem do definicji tego czym jest test jednostkowy. I tutaj pozwolę sobie przytoczyć cytat osoby znacznie mądrzejszej ode mnie:

I take this as a challenge. I’m happy to write integration tests. I insist on it. But a part of me registers the need for integration tests as a failure or limitation of my design skills. I’ll put that frontier in the back of my mind and a month or a year or a decade later bing I’ll figure out how to raise the level of abstraction, put more of the system in that happy state where I have complete confidence in it, and I’ll have new tools for thinking.

Kent Beck (ojciec koncepcji Test-Driven Development, cytat z felietonu „Unit” Tests?)

Dodatkowo ta sama osoba mówi wprost:

Czyli co? Chcesz powiedzieć, że mamy do czynienia z narzędziem do projektowania, a nie z czymś co pomaga w zapewnianiu jakości? Że testy jednostkowe mogą być testami integracyjnymi? A co z moją wspaniałą piramidą testów? Przecież jak nie będę mieć testów jednostkowych to ona mi się zawali!!!1111one (histeria, kurtyna).

Image result for burn him heretic cat
No to przyznać się, kto chce mnie spalić na stosie?

I tak i nie. To zależy. Mówiąc zupełnie poważnie, odpowiedź dostarczył niezawodny i dwukrotnie już cytowany Kent Beck:

When we use integers in a computation, we don’t feel compelled to write tests validating that our expectations for integers hold. We blithely expect that St. Peano will be watching over us, and he generally does (modulo modulo arithmetic–dang I’m feeling clever this morning).

Kent Beck (ojciec koncepcji Test-Driven Development, cytat z felietonu „Unit” Tests?).

Prawda, że to prawdziwe? Raczej absurdalnym założeniem jest testowanie czy arytmetyka liczb całkowitych działa poprawnia w naszym języku programowania. Czy nie możemy poczynić tego samego założenia wobec frameworku?

Moim zdaniem w analizowanym przypadku możemy. Zwłaszcza jeśli np. zależy nam na czasie, a rezygnacja z dogmatycznego podejścia tylko usprawni utrzymanie. Niczym nie ryzykuję proponując stwierdzenie, że testy (włączając w to jednostkowe) to przede wszystkim narzędzie, które może pomóc w osiągnięciu celu określonego poziomu jakości w projekcie.

Wszystko jest funkcją kosztu wytworzenia i utrzymania oraz ryzyka. Zauważcie, że Kent wprost mówi o arytmetyce liczb całkowitych, a nie ogólnie o arytmetyce. Dobrym kontrprzykładem, gdzie to mogłoby mieć sens to liczby rzeczywiste – kilka siwych włosów na jego skroni na pewno związanych jest z historią dot. właśnie z tym jak działa artytmetyka liczb zmiennoprzecinkowych w komputerach.

Skoro podejście narzędziowe wydaje się oczywiste, to dlaczego pojawia się tyle kontrowersji na temat różnych warstw testowania? Wydaje mi się, że głównym powodem jest właśnie ekstremizm w poglądach – i to nie dotyczy tylko testów, Kamila mówiła o tym wczoraj w odniesieniu do Scrum Guide (o nie, nie dam się sprowokować i nie powiem Wam co myślę o tym tworze ;)).

Podsumowanie

Zanim zakończę chciałbym jeszcze jedną rzecz uściślić – nie uważam, że podział pomiędzy testami jednostkowymi i integracyjnymi jest sztuczny, a np. mocki są bezwartościowe. Bezwartościowe jest traktowanie testów jednostkowych jako jedyny mechanizm, który daje wartość programistom i powinien być pisany przez nich.

Mam nadzieję, że w tak poprowadzonym wywodzie i dostarczonej argumentacji odpowiedź na tytułowe pytanie nasuwa się sama: Nigdy! Zawsze będziemy ich zawsze potrzebować. Jest jednak widoczny dość mocny trend, aby testy jednostkowe traktować dogmatycznie, pod katem tego kto powinien je pisać i czy są wartościowe – ja się z takim podejściem nie zgadzam. Dlatego celowo nie zamieściłem tutaj „dobrych rad” i pomysłów pewnego wuja.

Osobiści bliższe jest mi podejście, które reprezentuje Kent Beck. Zdecydowanie bardziej wolę płynne granice i chciałbym mieć więcej opcji w mojej skrzynce narzędziowej.

A z moich doświadczeń i obserwacji ekstremizm i dogmatyzm nikogo nie doprowadził do niczego dobrego. Zdecydowanie lepiej mieć otwartą głowę.