Jak często korzystacie z testów jednostkowych w swoich projektach?

Języków znam kilka, ale głównie z testami jednostkowymi miałem styczność jedynie w Pythonie i Rust.

W pythonie widzę że czasami niektóre repozytoria chwalą się coverage sięgającym niemal 100%.
W przypadku Rusta, ilość testów jest powiedzmy szczerze dosć ograniczona.

Mimo że uważam testy jednostkowe ogólnie za coś bardzo dobrego, to jednak bliżej mi do ich pisania tam gdzie niezbędne a nie dopychania ich na ilość.

W Rust, widzę że głównie pisze się testy do funkcji bez skutków ubocznych, czyli wrzucamy cos do środka i oczekujemy określonego wyniku(choć oczywiście są wyjątki).

W Pythonie jednak widzę że testuje się absolutnie wszystko, a to za sprawą że można zmockować niemal wszystko.
Trzeba dodać coverage do funkcji z pobieraniem informacji z bazy danych?
Nie ma sprawy, mockujemy połączenie i testujemy zwracanie wyjątku, losowych czy pustych danych.

Niby fajnie, ale jednak z tego co widzę to wydaje mi się że czasami takie funkcje testują bardziej to czy kod jest poprawnie zamokowany a nie samą logikę funkcji i są robione jako sztuka dla sztuki(lub po to by podbić coverage).
Często widzę że też takimi testami próbuje się testować, co się stanie jeśli typy nie są poprawne, coś co niemal nie występuje w językach silnie typowanych typu Rust lub C++, bo już kompilator odrzuca sporą część niepoprawnego kodu.

Jakie są wasze opinie o dużym coverage w zależności od języka dla którego testy są pisane?

#programowanie
93e396ff-4cb9-4db2-8fb0-c72988849d72

W jakie wartości co do testów jednostkowych celujecie w swoich projektach?

121 Głosów
rayros

Jak mam czas to pisze testy jak nie mam to tam gdzie coś poprawiałem bo był bug.

szczekoscisk

Często testy jednostkowe to sztuka dla sztuki a taki PO/SM może nacieszyć się pokryciem kodu nie wiedząc w sumie po co to jemu.

Podstawą powinny być testy usecase'ów bo na tym nam glownie zależy. Jeśli taki test poleci to znaczy że implementacja jest walnięta. A jeśli dobrze napisany test nie wykrył błędej implementacji to też nas to nie boli bo de facto błąd nie wpłynie na używanie serwisu/apki/libki ect.

No i testujac zachowania a nie implementację nie betonujemy sobie kodu testami.

wombatDaiquiri

@qarmin jak nie jestem w stanie napisać testu to prawdopodobnie nie wiem jak działa funkcja. Gdybym wiedział, to bym ją przepisał w sposób który umożliwia testowanie.


Piszę w go, ale to nie jest kwestia języka, tylko budowania modelu mentalnego kodu z którym pracujesz.

macgajster

W obecnej robocie tylko raz robiłem testy fw przez ponad trzy lata pracy. Mój kod nie podlega review, a zacząłem uczyć się programowania dopiero tutaj. Przynajmniej dobrze nauczyłem się robić babole ( ͡° ͜ʖ ͡°)

ZohanTSW

Zawsze staram się używać testów, daje to zwyczajnie pewność, że jakaś funkcja robi co powinna (o ile jest poprawnie przetestowana). Jak sobie przypominam jakieś błędy w kodzie to wykryte zostały albo w nieotestowanej części, albo podczas pisania testu. Wiele razy testy uratowały mi dupę i uświadomiły na co tak naprawdę moja zmiana wpływa. Czy testy bywają sztuką dla sztuki? Jeśli tak, to w tym jest problem, a nie w samych testach.

Nie rozumiem do końca "betonowania sobie kodu testami", ale brzmi jak sprawdzanie czy funkcja A woła funkcję B - nie zbyt lubię pisać testy w ten sposób, ale to powinno być wykorzystane gdy używamy biblioteki 3rd party.

Ogólnie uważam że zawsze powinno się pisać jakieś testy i unikać podejścia "po co testować jeśli wydaje ci się że to powinno działać".

A no i wyjątkiem mogą być trywialne gettery i settery - nie widzę sensu jeśli nic przy okazji się nie dzieje w takiej funkcji.

globalbus

@qarmin niektóre rzeczy są nietestowalne jednostkowo. Np mam sobie bibliotekę operującą na typach w bazie Oracle. Zaślepianie metod sterownika oracle byłoby bez sensu. Dużo lepiej sprawdza jej działanie test integracyjny z bazą na kontenerze dockerowym.

cweliat

@qarmin z testami tak na porzadnie mialem do czynienia tylko raz i do projektu pythonowego nad ktorym pracowalem dodal je taki mega ogarniety senior dev. Przy rozwoju projektu, jak testy wypluwaly bledy, to zwykle byla kwestia chujowego testu, a nie bledu w kodzie. Takze albo testy chuja warte, albo taka ich rola

mnie_tu_nie_ma

Generalnie klasy mozesz podzielic ze wzgledu na ich liczbę zaleznosci (dependencji) oraz ze wzgledu na ich złożoność na 4 typy:

- malo zależności, mala złożoność, typowe kontenerki danych ktore mają gettery i settery. Na to nie powinno się pisac testow ale używając tych klas bezsposrednio w testach pozostalych klas niejako przy okazji zwiekszasz tez coverage na te klasy

- malo zaleznosci, duza zlozonosc, tutaj wpadają algorytmy czy reguły biznesowe, które dostają np liste itemow i ją sortuja albo zwracają max value. Fajne i latwe w testowaniu

- duzo zaleznosci, mala zlozonosc, tutaj trafia nasz glue code ktory glownie przerzuca dane z jednego miejsca w inne. Np controller ktory otrzymuje z widoku event "user wcisnal enter" i w reakcji na to wola metode "networkService.logout". Mozna to testowac jednostkowo, chociaz wtedy zazwyczaj nie ma wyniku dzialania takiego kodu (asercji na zwracanym wyniku) tylko weryfikacja czy wywolalismy odpowiednie metody na mockach (w tym wypadku networkService). Z tego powodu lepszy moze byc test integracyjny lub end2end

-dużo zależności, duża złożoność - zjebałeś, zrefaktoruj dzieląc na mniejsze klasy


Do tego warto wiedzieć ze sa dwie szkoly, klasyczna oraz London school, ktore mają zasadnicze roznice w tak podstawowych pojeciach jak izolacja testu. Przez to jedna szkoła będzie sugerowac mokowanie wszystkich zaleznosci testowanej klasy (aby testowac tylko jej zachowanie) a druga tylko te zaleznosci które blokują możliwość uruchamiania testow rownolegle i w dowolnej kolejnosci (np instancja bazy danych gdzie dwa testy mogą sobie nadpisac potrzebne dane).

mnie_tu_nie_ma

Generalnie są cale książki na ten temat i na Twoje pytania odpowiedz to "to zalezy" :) ale osobiscie jako dev z okolo 15 latami doswiadczenia pisze jednostkowe z uzyciem TDD, w takich ilosciach, ze coverage wychodzi w okolicach 70-90% bez sztucznego klepania testow dla getterow i setterow. Dzieki temu spie spokojnie

Atexor

Nie jestem tak biegły w kodowanie, czystych testów jednostkowych nie piszę, niemniej jak piszę macra do programu którego używam, to badam każdą jedną funkcję. Niestety ten soft mimo potencjału był tworzony przez debili którzy zlecili jego działanie debili na stażu i nawet, mimo że po API zwracam konkretną wartość, to raz się zwraca, a raz nie (albo nic, albo zwraca dane z dupy) i szukam workaroundów, coś ala scrapowania tego co widzę. Prócz tego jest wiele podobnych rzeczy, które wymagają różnego podejścia - raz tablic dynamicznych, raz statycznych, raz obiektów, innym razem tylko doublów.


Pomaga mi to jednak rozwinąć się na nieszablonowe myślenie, po pierwsze alternatywne, lepsze (kub gorsze, ale nadal działające) rozwiązania, po drugie dzięki temu znajduję swoje błędy, nieprzewidziane przypadki które mogłyby spowodować wysypanie się softu.


Według mnie dodając coś zawsze warto choć raz to przetestować - zarówno na wszelakie dane, jak i idiotoodporność, gdy np. ktoś wklei tekst a program oczekuje liczbę, albo da liczbę z separatoem w dziesiętnym, a soft wymaga przecinka.

argonauta

Klepię testy unitowe i integracyjne w standardzie. Może w trakcie pisania kodu nie docenisz ich wagi, ale... ktoś (może nawet Ty) kto będzie modyfikował kod w przyszłości doceni.


Jeżeli jest to one-man project to wtedy raczej robię unity tylko fragmentów kodu które są bardzo specyficzne/krytyczne.

epsilon_eridani

@qarmin koledzy zdaję się wyczerpali temat, ja tez stoje po stronie pisania testów, od siebie jeszcze dodam, że testy naturalnie tworzą dokumentację projektu. Najłatwiej jest sprawdzić jak się zachowuje komponent za pomocą testów i najlepiej naprawić buga najpierw pisząc test do przypadku.

PanPaweuDrugi

@qarmin ja bym przede wszystkim chciał podkreślić, że testy jednostkowe to głównie narzędzie służące do projektowania, wymuszające stosowanie dobrych praktyk. W sumie czyste unit testy mają sens przede wszystkim w TDD, jeśli piszemy je później niż kod, to sens ich pisania jest dyskusyjny. Dobrze się natomiast sprawdzają w roli żywej dokumentacji. To testy integracyjne powinny służyć do wykrywania regresji, tych można stworzyć zdecydowanie mniej, za to każdy powinien mieć wielokrotnie większe pokrycie kodu. W praktyce, jeśli zespół nie stosuje TDD, to właśnie na takim rodzaju testów warto się skupić.


Pracuję przy takim projekcie w node, gdzie ktoś sprytny testuje timery bez użycia mocków, test po prostu czeka aż te timery odczekają swoje, nic mnie tak nie wkurwia jak odpalanie testów w tym projekcie xD.

Flaaj

po pracy w januszexie-startupie, gdzie nigdy nie bylo czasu na testy, nauczyłem się, jaką mają wartość. Zawsze na koniec projektu przy małej zmianie koncepcji ze strony klienta, caly kod sie zaczynał się jebać, bo choćby nie wiem co, nie jesteś w stanie zawsze mieć w głowie całego projektu.


Odkąd odszedłem z tej firmy, zacząłem robić wszystko uzywając TDD. Bez TDD twój kod = gówno. Choćby nie wiadomo jak czytelny i sprytny, bez dobrych testów nie jest niczego warty.

Zaloguj się aby komentować