Od razu przyznam, że jestem noobem jeśli chodzi o testy jednostkowe. Nigdy nie miałem szczęścia być w projekcie, gdzie testy były zrobione z głową - zazwyczaj albo ich nie było albo każdy pisał jak uważał. Zazwyczaj były to testy pisane w ten sposób, że testujemy klasę X a wszystkie zależności to mock. Czyli generalnie każda klasa ma (bądź powinna mieć) swój test. Takie podejście jest też wspierane przez IDE, które potrafi dzisiaj wygenerować stub dla testu umieszczając go w miejscu odzwierciedlającym miejsce w strukturze katalogów testowanej klasy.
Szczerze mówiąc wydawało mi się to zawsze... głupie. Refactoring większego systemu to katorga bo zmienisz jakąś poboczną klasę i nagle testy się sypią bo nie zmieniłeś mocków itp. Pisanie testów dla wszystkich klas wydaje się tez często overkillem, gdy klasę można dość łatwo i sprawnie przetestować pośrednio... No ale przecież to Unit Test, więc nie testujemy systemu tylko daną klasę... No właśnie czy tak jest?
Ostatnio sporo czytam o różnych zagadnieniach aby zobaczyć czym żyje świat i trafiłem między innymi na ciekawą książkę "Unit Testing Principles, Practices, and Patterns", która przedstawia wszystko trochę inaczej. Ogólnie (trochę uproszczę, bo trudno opisać całą filozofię w 5 punktach i przy okazji pewnie coś przekręcę):
- powinniśmy unikać mocków dla wszystkiego co odbywa się w naszej aplikacji (domenie)
- mocki stosujemy tylko do rzeczy typu baza, api etc - ewentualnie może do czegoś gdzie inaczej musielibyśmy stworzyć jakiś potężny graf zależności - tu jednak znowu to raczej problemem jest nasz kod, który te grafy zależności rozdmuchuje.
- im więcej naszego kodu domenowego wywołuje test poprzez zależności tym lepiej, bo dzięki temu wyłapiemy więcej błędów
- test, który pośrednio wywoła dużą ilość kodu spoza testowanej klasy nadal jest testem jednostkowym - nikt w końcu nie powiedział, że jednostką jest klasa
- według autora w testach jednostkowych bardziej trzeba się skupić na jednostce "zachowania" niż jakiejś sztuczniej wydzielonej jednostce kodu (np. funkcji, klasy)
Powiem szczerze, że bardzo to do mnie trafiło i przywróciło chęć do pisania testów. Teraz testów piszę znacznie mniej, bo wiele klas testuję po prostu pośrednio, zwłaszcza takich, które nie mają rozbudowanej logiki biznesowej i mają mało powodów do zmiany. Bardzo zgrało się to z moim zmienionym podejściem do samego programowania, gdzie staram się rozdzielać domenę od reszty kodu i testuję głównie właśnie domenę. Mam wrażenie, że takie testy znacznie lepiej spełniają swoją rolę i do tego są o wiele mniej podatne na efekty uboczne przy refaktoringu. Ogólnie autor bardzo trafnie wypunktował moim zdaniem wiele patologii Unit Testów, które mnie męczyły.
Oczywiście jak klasa ma jakąś rozbudowaną logikę to piszę do niej testy szczegółowe mimo tego, że jest testowana pośrednio przez inne testy to jednak test szczegółowy też się przydaje, ale teraz jestem zdania, jak autor przytoczonej przeze mnie książki, że mocki to zło w 9 na 10 przypadków. Póki nie zahaczam o coś poza domeną (np. ORM czy na przykład system kolejkowy) to nawet test, który przeora połowę domeny traktuję jako jednostkowy.
Jak to wygląda u Was?