Perspektywiczny:
Cofnijmy się więc i zapytajmy, w czym TDD próbuje nam pomóc. TDD stara się pomóc nam ustalić, czy nasz kod jest poprawny, czy nie. I poprawnie, mam na myśli „czy kod spełnia wymagania biznesowe?” Chodzi o to, że wiemy, że zmiany będą wymagane w przyszłości i chcemy mieć pewność, że nasz kod pozostanie poprawny po ich wprowadzeniu.
Podnoszę tę perspektywę, ponieważ myślę, że łatwo jest zagubić się w szczegółach i stracić z oczu to, co próbujemy osiągnąć.
Zasady - SAP:
Chociaż nie jestem ekspertem w TDD, myślę, że brakuje ci części tego, czego stara się nauczać Zasada Single Assertion (SAP). SAP można przekształcić w „testowanie jednej rzeczy naraz”. Ale TOTAT nie zsuwa się z języka tak łatwo, jak SAP.
Testowanie jednej rzeczy na raz oznacza, że skupiasz się na jednej sprawie; jedna ścieżka; jeden warunek brzegowy; jeden przypadek błędu; jedno co za test. Podstawową ideą jest to, że musisz wiedzieć, co się zepsuło, gdy przypadek testowy się nie powiedzie, abyś mógł szybciej rozwiązać problem. Jeśli w teście przetestujesz wiele warunków (tj. Więcej niż jedną rzecz), a test się nie powiedzie, masz o wiele więcej pracy. Najpierw musisz określić, które z wielu przypadków zakończyły się niepowodzeniem, a następnie dowiedzieć się, dlaczego ta sprawa zakończyła się niepowodzeniem.
Jeśli testujesz jedną rzecz na raz, zakres wyszukiwania jest znacznie mniejszy, a wada jest wykrywana szybciej. Pamiętaj, że „testowanie jednej rzeczy na raz” niekoniecznie wyklucza patrzenie na więcej niż jeden wynik procesu na raz. Na przykład, podczas testowania „znanej dobrej ścieżki”, mogę oczekiwać konkretnej wartości końcowej, foo
a także innej wartości, bar
i mogę to zweryfikować foo != bar
w ramach mojego testu. Kluczem jest logiczne zgrupowanie kontroli wyników na podstawie testowanej sprawy.
Zasady - PMP:
Podobnie, myślę, że brakuje ci trochę tego, czego nauczy nas zasada prywatnej metody (PMP). PMP zachęca nas do traktowania systemu jak czarnej skrzynki. Dla danego wejścia powinieneś otrzymać dane wyjściowe. Nie obchodzi Cię, w jaki sposób czarna skrzynka generuje dane wyjściowe. Dbasz tylko o to, aby Twoje wyniki były zgodne z danymi wejściowymi.
PMP jest naprawdę dobrą perspektywą do spojrzenia na aspekty API twojego kodu. Może także pomóc w określeniu zakresu tego, co musisz przetestować. Zidentyfikuj punkty interfejsu i sprawdź, czy spełniają warunki swoich umów. Nie musisz przejmować się tym, w jaki sposób metody ukryte w interfejsie (znane również jako prywatne) wykonują swoje zadanie. Musisz tylko sprawdzić, czy zrobili to, co mieli zrobić.
Applied TDD ( dla Ciebie )
Więc twoja sytuacja stanowi nieco zmarszczkę poza zwykłą aplikacją. Metody aplikacji są stanowe, więc ich wyniki zależą nie tylko od danych wejściowych, ale także od wcześniejszych działań. Jestem pewien, że powinienem <insert some lecture>
tutaj powiedzieć o byciu okropnym i bla bla bla bla, ale to naprawdę nie pomaga rozwiązać twojego problemu.
Zakładam, że masz jakąś tabelę diagramów stanów, która pokazuje różne potencjalne stany i co należy zrobić, aby uruchomić przejście. Jeśli nie, będziesz go potrzebować, ponieważ pomoże to wyrazić wymagania biznesowe dla tego systemu.
Testy: Najpierw skończysz z zestawem testów, które wprowadzają zmianę stanu. Idealnie, będziesz mieć testy, które sprawdzają pełen zakres zmian stanu, które mogą wystąpić, ale widzę kilka scenariuszy, w których może nie być konieczne przejście w pełnym zakresie.
Następnie musisz zbudować testy, aby sprawdzić poprawność przetwarzania danych. Niektóre z tych testów stanu zostaną ponownie wykorzystane podczas tworzenia testów przetwarzania danych. Załóżmy na przykład, że masz metodę, Foo()
która ma różne wyniki oparte na stanach Init
i State1
. Będziesz chciał użyć swojego ChangeFooToState1
testu jako kroku konfiguracji w celu przetestowania wyjścia, gdy „ Foo()
jest w State1
”.
Podejście to ma pewne implikacje, o których chcę wspomnieć. Spoiler, tutaj właśnie rozwścieczę purystów
Po pierwsze, musisz zaakceptować fakt, że używasz czegoś jako testu w jednej sytuacji, a konfiguracji w innej sytuacji. Z jednej strony wydaje się, że jest to bezpośrednie naruszenie SAP. Ale jeśli logicznie tworzysz ramy dla ChangeFooToState1
dwóch celów, nadal spełniasz duch tego, czego uczy nas SAP. Kiedy musisz upewnić się, że Foo()
zmiany są w stanie, użyj go ChangeFooToState1
jako testu. A kiedy trzeba zweryfikować Foo()
dane wyjściowe State1
„ in in ”, używasz ChangeFooToState1
jako konfiguracji.
Po drugie, z praktycznego punktu widzenia nie będziesz chciał w pełni losowych testów jednostkowych dla swojego systemu. Przed uruchomieniem testów sprawdzania poprawności danych wyjściowych należy uruchomić wszystkie testy zmiany stanu. SAP jest rodzajem przewodniej zasady tego zamówienia. Aby stwierdzić, co powinno być oczywiste - nie można użyć czegoś jako konfiguracji, jeśli nie powiedzie się to jako test.
Składając to razem:
Za pomocą diagramu stanu wygenerujesz testy obejmujące przejścia. Ponownie, korzystając ze schematu, generujesz testy obejmujące wszystkie przypadki przetwarzania danych wejściowych / wyjściowych sterowane stanem.
Jeśli zastosujesz to podejście, bloated, complicated, long, and difficult to write
testy powinny być nieco łatwiejsze do zarządzania. Zasadniczo powinny one być mniejsze i powinny być bardziej zwięzłe (tj. Mniej skomplikowane). Powinieneś zauważyć, że testy są również bardziej niezależne lub modułowe.
Nie twierdzę, że proces ten będzie całkowicie bezbolesny, ponieważ pisanie dobrych testów wymaga pewnego wysiłku. Niektóre z nich nadal będą trudne, ponieważ mapujesz drugi parametr (stan) na kilka swoich przypadków. Nawiasem mówiąc, powinno być nieco bardziej oczywiste, dlaczego system bezstanowy jest łatwiejszy do zbudowania testów. Ale jeśli dostosujesz to podejście do swojej aplikacji, powinieneś stwierdzić, że jesteś w stanie udowodnić, że aplikacja działa poprawnie.