Ortogonalność testów jednostkowych a zakończenie testów jednostkowych

14

Piszę testy jednostkowe systemu sterowania dla gry wideo. System ma kilka zachowań (unikaj tego obszaru z powodu przyczyny A, unikaj tego obszaru z powodu przyczyny B, każde z nich dodaje trochę kontekstu do mapy regionu. Oddzielna funkcja następnie analizuje mapę i wykonuje pożądany ruch.

Mam problem z podjęciem decyzji, jak napisać testy jednostkowe dla zachowań. Jak sugeruje TDD, interesuje mnie tylko to, jak zachowania wpływają na pożądany ruch. Na przykład unikanie z powodu powodu powinno skutkować odejściem od sugerowanej złej pozycji. Nie obchodzi mnie, w jaki sposób i dlaczego zachowanie dodaje kontekst do mapy, tyle że pożądany ruch jest z dala od pozycji.

Więc moje testy dla każdego zachowania konfigurują zachowanie, zapisują je na mapie, a następnie wykonują funkcję parsowania mapy w celu wypracowania pożądanego ruchu. Jeśli ten ruch spełnia moje wymagania, jestem szczęśliwy.

Jednak teraz moje testy zależą zarówno od poprawnego działania, jak i od prawidłowej funkcji analizy mapy. Jeśli funkcja parsowania zawiedzie, dostanę setki nieudanych testów zamiast kilku. Wiele przewodników po pisaniu testów sugeruje, że jest to zły pomysł.

Jeśli jednak przetestuję bezpośrednio wyniki wyjściowe zachowań, wyśmiewając mapę, to na pewno zbyt mocno wiążę się z implementacją? Jeśli mogę uzyskać ten sam pożądany ruch z mapy, używając nieco innego zachowania, testy powinny nadal przejść.

Więc teraz cierpię na dysonans poznawczy. Jak najlepiej ustrukturyzować te testy?

tenpn
źródło
... nie jestem pewien, czy jest magiczna odpowiedź. Zasadniczo testujesz rzeczy, które mogą się zepsuć. Idealnie byłoby, gdybyś w magiczny sposób mógł stwierdzić, które testy niskiego poziomu będą już wystarczająco objęte testami wysokiego poziomu, aby nie potrzebowały własnych testów jednostkowych niższego poziomu. Innym sposobem spojrzenia na to jest: od czasu niepowodzenia testu do momentu rozwiązania problemu przez programistę, ile czasu minie? Chcesz, żeby ten czas był niski. Jeśli nie wykonałeś żadnych jednostek, a jedynie doskonałe testy funkcjonalne (pełne pokrycie wysokiego poziomu), ten czas byłby nadal zbyt długi. Spróbuj użyć tego jako przewodnika heurystycznego.
Calphool

Odpowiedzi:

10

W idealnym świecie rzeczywiście istniałby zestaw idealnie ortogonalnych testów jednostkowych, wszystkie na tym samym poziomie abstrakcji.

W prawdziwym świecie zwykle masz testy na wielu różnych poziomach aplikacji, więc często testy wyższego poziomu wykonują funkcje, które zostały już przetestowane przez dedykowane testy niższego poziomu. (Wiele osób woli nazywać takie testy podsystemem / testem integracji wyższym poziomem niż testami jednostkowymi; niemniej jednak mogą one nadal działać w tym samym systemie testów jednostkowych, więc z technicznego punktu widzenia nie ma dużej różnicy).

Nie sądzę, że to zła rzecz. Chodzi o to, aby Twój kod został przetestowany w najlepszy sposób, który pasuje do twojego projektu i twojej sytuacji, a nie przestrzeganie „idealnego sposobu”.

Péter Török
źródło
Wydaje mi się, że głównym celem autora było to, czy należy używać kodów pośredniczących / próbnych, czy też rzeczywistych implementacji do testów wyższego poziomu
SiberianGuy
2

Tego rodzaju testy wymyślają symulacje. Główna idea: piszesz próbkę dla swojego obiektu (mapa, zachowanie, postać, ...), a następnie piszesz testy przy użyciu tej próbki zamiast rzeczywistego obiektu. Ludzie czasami nazywają fałszywymi odcinkami i wierzę, że są inne słowa na oba.

W twoim przypadku pisałbyś próbną mapę, ilekroć chcesz przetestować zachowania, oraz inne próbne zachowanie, ilekroć chcesz przetestować mapę. Twoje kpiny byłyby idealnie prostsze niż rzeczywiste kpiące zachowania, zawierające tylko metody lub zmienne, których naprawdę potrzebujesz do tego testu. Być może będziesz musiał napisać inną próbkę dla każdego testu lub możesz być w stanie ponownie użyć niektórych prób. Niezależnie od tego, powinny one nadawać się do testu i nie powinny starać się być jak najbardziej realistyczne.

Jeśli podasz przykłady map lub zachowań, być może ktoś może podać przykłady kpiny, które możesz napisać. Nie ja, ponieważ nigdy nie programowałem bardziej zaawansowanej gry wideo niż Pong, a nawet wtedy śledziłem książkę, ale być może ktoś dobrze zorientowany zarówno w testowaniu jednostkowym, jak i tworzeniu gier.

trysis
źródło
0

Myślę, że próbujesz przetestować rzeczy, które są znacznie wyżej niż jednostka.

Większość testów behawioralnych wymagałaby pewnej inteligencji, aby stwierdzić, czy zachowuje się poprawnie. Nie można tego łatwo zrobić za pomocą testów automatycznych.

oenone
źródło
dlatego wspomniałem o zwięzłości. Potrafię bardzo łatwo pisać małe testy jednostkowe, aby przetestować poszczególne wiersze kodu w zachowaniu, i zrobiłem to, ale zależy to od odczytu wyniku funkcji parsowania mapy. Żaden z moich testów zachowania nie jest duży, każdy z nich testuje tylko jeden element funkcjonalności zachowania.
tenpn