Interfejs w programowaniu możemy rozumieć przynajmniej dwojako. Po pierwsze: interfejs użytkownika, czyli sposób na interakcję z aplikacją. Po drugie: interfejs jako kontrakt, implementowany przez klasy. Testy ładnie wpasowują się w… obie definicje!
[blogvember2016 no=”1″]
Testy jako UI… a raczej DI
Interfejs użytkownika – User Interface – charakteryzuje się tym, że możemy po nim pochodzić, poeksperymentować, poklikać. Nakazać aplikacji COŚ zrobić.
A testy? Są doskonałym interfejsem programisty! Developer Interface. Mając aplikację porządnie pokrytą testami jesteśmy w stanie, nawet bez jej uruchamiania, zmusić ją do działania. Niezmiernie przydatna możliwość.
Nie czekamy na całą kompilację, nie czekamy na wdrożenie, rozgrzanie serwera. Uruchamiamy test i… i już. Oszczędzamy masę czasu.
Dawno temu natknąłem się na ciekawą anegdotkę. Podobno jedna z linii lotniczych w USA tak głęboko “weszła” w BDD (Behavior Driven Development), że nawet obsługa klienta poruszała się po systemie za pomocą… testów właśnie! Wyobraź sobie sytuację: podchodzisz do stanowiska, chcesz kupić bilet, a babka za ladą mówi: “Już już, puszczam test sprawdzający, czy mamy wolne miejsca na ten lot“. Szczena na ziemi, nie? Mam nadzieję, że to prawda.
Ba, mało tego: każdy test możemy uruchomić z podłączonym debuggerem! To bardzo często – a po kilku latach zdobywania doświadczenia: prawie zawsze – eliminuje konieczność podpinania się debuggerem do całego, wielkiego, działającego procesu. Nie musimy klikać na chybił-trafił w celu zreprodukowania błędu. Zamiast tego modelujemy scenariusz w postaci kodu testującego -> stawiamy breakpoint -> “run with debugger” -> done.
Przez lata całe nie debuggowałem całej aplikacji. Godziny, albo i nawet DNI, przez to zaoszczędziłem. Już w 2011r cytowałem Uncle Boba Martina:
Would you rather Test-First or Debug-Later?
No właśnie…
Uwaga, szkolonko!
Korzystając z okazji, zapraszam na moje jednodniowe szkolenie otwarte z pisania testów w .NET. Wszystkie szczegóły znajdziesz tutaj. Jeszcze tylko przez kilka dni można kupić bilet z rabatem 25%!
A co z drugą definicją interfejsu?
Testy jako interfejs – kontrakt
Dobrze napisane testy pełnią rolę dokumentacji naszego kodu. Dokumentacji, która – w przeciwieństwie do standardowej, tekstowej – zawsze będzie aktualna. Nigdy się nie rozsynchronizuje.
Pracowałem w wielu firmach. Niejednokrotnie pierwsze dni w nowym miejscu spędzałem czytając dziesiątki stron “dokumentacji technicznej” w Wordzie. Tylko po to, żeby na koniec usłyszeć: “wiesz co, w sumie to tego dokumentu i tak nikt od miesięcy nie aktualizował, więc pewnie w kodzie to wygląda trochę inaczej“. Z testami nie ma tego problemu. Muszą opisywać faktyczny, aktualny kod. W przeciwnym wypadku zaczną się wywalać.
Testy mówią programiście CO aplikacja robi. Niekiedy nie skupiają się nawet na tym JAK. Często szczegóły implementacyjne nie są widoczne z poziomu testów. I nie powinny być. W końcu mamy święty cykl TDD (więcej o możliwych podejściach do TDD poczytasz w tekście “Niezawodny sposób na naukę testów jednostkowych“):
Refactoring to proces modyfikacji struktury kodu bez zmiany jego działania. A więc: bez dotykania testów. Skoro tak, to testy są kontraktem. A kod: jego implementacją.
Sprytne, nie?