Makieta obiektu
W programowaniu obiektowym obiekty symulowane to symulowane obiekty, które naśladują zachowanie rzeczywistych obiektów w kontrolowany sposób, najczęściej w ramach inicjatywy testowania oprogramowania . Programista zwykle tworzy symulowany obiekt, aby przetestować zachowanie innego obiektu, w podobny sposób, w jaki projektant samochodów używa manekina do testów zderzeniowych do symulacji dynamicznego zachowania człowieka podczas zderzenia pojazdu. Technika ta ma również zastosowanie w programowaniu generycznym .
Motywacja
W teście jednostkowym symulowane obiekty mogą symulować zachowanie złożonych, rzeczywistych obiektów i dlatego są przydatne, gdy prawdziwy obiekt jest niepraktyczny lub niemożliwy do włączenia do testu jednostkowego. Jeśli obiekt ma jedną z poniższych cech, przydatne może być użycie w jego miejsce symulowanego obiektu:
- obiekt dostarcza wyników niedeterministycznych (np. aktualny czas lub aktualna temperatura);
- ma stany trudne do wytworzenia lub odtworzenia (np. błąd sieci);
- jest powolny (np. kompletna baza danych , którą trzeba by zainicjalizować przed testem);
- jeszcze nie istnieje lub może zmienić zachowanie;
- musiałby zawierać informacje i metody wyłącznie do celów testowych (a nie do swojego rzeczywistego zadania).
Na przykład program budzika, który powoduje dzwonienie dzwonka o określonej godzinie, może pobierać aktualny czas z usługi czasu. Aby to sprawdzić, test musi poczekać do czasu alarmu, aby wiedzieć, czy zadzwonił dzwonkiem prawidłowo. Jeśli zamiast usługi czasu rzeczywistego używana jest usługa symulowana, można ją zaprogramować tak, aby podawała czas bicia dzwonka (lub jakikolwiek inny czas) niezależnie od czasu rzeczywistego, tak aby program budzika mógł być testowany w izolacji.
Szczegóły techniczne
Pozorowane obiekty mają ten sam interfejs , co rzeczywiste obiekty, które naśladują, dzięki czemu obiekt kliencki pozostaje nieświadomy tego, czy używa obiektu rzeczywistego, czy symulowanego. Wiele dostępnych frameworków symulowanych obiektów pozwala programiście określić, które iw jakiej kolejności metody zostaną wywołane na symulowanym obiekcie oraz jakie parametry zostaną im przekazane, a także jakie wartości zostaną zwrócone. W ten sposób zachowanie złożonego obiektu, takiego jak gniazdo sieciowe, może być naśladowane przez symulowany obiekt, co pozwala programiście odkryć, czy testowany obiekt odpowiednio reaguje na różnorodne stany, w jakich mogą znajdować się takie symulowane obiekty.
Kpiny, podróbki i zakładki
Klasyfikacja między makietami, podróbkami i odcinkami jest wysoce niespójna w całej literaturze. Jednak zgodnie z literaturą wszystkie one reprezentują obiekt produkcyjny w środowisku testowym, udostępniając ten sam interfejs.
Który spośród mock , fake , czy stub jest najprostszy, jest niespójny, ale najprostszy zawsze zwraca wcześniej ustalone odpowiedzi (jak w metodzie stub ). Po drugiej stronie spektrum najbardziej złożony obiekt będzie w pełni symulował obiekt produkcyjny z pełną logiką, wyjątkami itp. To, czy którekolwiek z trio pozorowanego, fałszywego lub pośredniego pasuje do takiej definicji, jest ponownie niespójne w całym literatura.
Na przykład próbna, fałszywa lub pośrednicząca implementacja metody między dwoma końcami spektrum złożoności może zawierać asercje w celu zbadania kontekstu każdego wywołania. Na przykład symulowany obiekt może potwierdzić kolejność wywoływania jego metod lub zapewnić spójność danych między wywołaniami metod.
W książce The Art of Unit Testing makiety są opisane jako fałszywy obiekt, który pomaga zdecydować, czy test się nie powiódł, czy przeszedł pomyślnie, poprzez sprawdzenie, czy nastąpiła interakcja z obiektem. Wszystko inne jest definiowane jako kod pośredniczący. W tej książce podróbki to wszystko, co nie jest prawdziwe, co w zależności od ich zastosowania może być albo kodem pośrednim , albo kpiną .
Ustalanie oczekiwań
Rozważmy przykład, w którym wyśmiewano podsystem autoryzacji. Symulowany obiekt implementuje isUserAllowed(task : Task) : boolean
, aby dopasować ją do rzeczywistej klasy autoryzacji. Wiele korzyści wynika z tego, że ujawnia również isAllowed : boolean
, której nie ma w klasie rzeczywistej. Pozwala to kodowi testowemu łatwo ustawić oczekiwanie, że użytkownik otrzyma lub nie otrzyma pozwolenia w następnym wywołaniu, a tym samym łatwo przetestować zachowanie reszty systemu w obu przypadkach.
Podobnie, ustawienia tylko próbne mogą zapewnić, że kolejne wywołania podsystemu spowodują zgłoszenie wyjątku , zawieszenie się bez odpowiedzi lub zwrócenie wartości null
itp. W ten sposób możliwe jest opracowanie i przetestowanie zachowań klienta pod kątem realistycznych warunków błędu w back- końcowych podsystemów, jak również ich oczekiwanych odpowiedzi. Bez tak prostego i elastycznego systemu próbnego testowanie każdej z tych sytuacji może być zbyt pracochłonne, aby można je było odpowiednio rozważyć.
Zapisywanie ciągów dziennika
save(person : Person)
pozorowanego obiektu bazy danych może nie zawierać dużo (jeśli w ogóle) kodu implementacji. Może sprawdzić istnienie i być może poprawność obiektu Person przekazanego do zapisania (patrz powyżej omówienie fake vs. mock), ale poza tym może nie być żadnej innej implementacji.
To stracona szansa. Próbna metoda może dodać wpis do ciągu dziennika publicznego. Wpis nie może być większy niż „Osoba zapisana” lub może zawierać pewne szczegóły z instancji obiektu osoby, takie jak imię i nazwisko lub identyfikator. Jeśli kod testowy sprawdza również ostateczną zawartość ciągu logów po różnych seriach operacji na próbnej bazie danych, to można zweryfikować, czy w każdym przypadku została wykonana dokładnie oczekiwana liczba zapisów bazy danych. Może to znaleźć niewidoczne w inny sposób błędy obniżające wydajność, na przykład, gdy programista, zdenerwowany utratą danych, zakodował powtarzające się wywołania save ()
gdzie wystarczyłby jeden.
Użyj w programowaniu opartym na testach
Programiści pracujący metodą test-driven development (TDD) podczas pisania oprogramowania wykorzystują makiety obiektów. Pozorowane obiekty spełniają interfejsu i zastępują bardziej złożone obiekty rzeczywiste; w ten sposób pozwalają programistom pisać i testować funkcjonalność w jednym obszarze bez wywoływania złożonych klas bazowych lub współpracujących . Używanie obiektów makiety pozwala programistom skoncentrować swoje testy na zachowaniu testowanego systemu bez martwienia się o jego zależności. Na przykład testowanie złożonego algorytmu opartego na wielu obiektach znajdujących się w określonych stanach można wyraźnie wyrazić za pomocą symulowanych obiektów zamiast rzeczywistych obiektów.
Oprócz problemów związanych ze złożonością i korzyściami uzyskanymi z tego rozdzielenia problemów , w grę wchodzą praktyczne kwestie związane z szybkością. Opracowanie realistycznego oprogramowania przy użyciu TDD może z łatwością obejmować kilkaset testów jednostkowych. Jeśli wiele z nich indukuje komunikację z bazami danych, usługami internetowymi i innymi pozaprocesowymi lub sieciowymi , zestaw testów jednostkowych szybko stanie się zbyt wolny, aby można go było regularnie uruchamiać. To z kolei prowadzi do złych nawyków i niechęci dewelopera do utrzymania podstawowych założeń TDD.
Gdy fałszywe obiekty zostaną zastąpione prawdziwymi, kompleksowa funkcjonalność będzie wymagała dalszych testów. Będą to testy integracyjne niż jednostkowe.
Ograniczenia
Użycie próbnych obiektów może ściśle powiązać testy jednostkowe z implementacją testowanego kodu. Na przykład wiele platform symulowanych obiektów umożliwia programistom sprawdzenie kolejności i liczby wywołań metod symulowanych obiektów przez testowany rzeczywisty obiekt; późniejsza refaktoryzacja testowanego kodu może zatem spowodować niepowodzenie testu, mimo że wszystkie metody wyśmiewanych obiektów nadal są zgodne z umową z poprzedniej implementacji. Pokazuje to, że testy jednostkowe powinny testować zewnętrzne zachowanie metody, a nie jej wewnętrzną implementację. Nadmierne użycie próbnych obiektów w ramach zestawu testów jednostkowych może spowodować dramatyczny wzrost ilości czynności konserwacyjnych, które należy wykonać na samych testach podczas ewolucji systemu w miarę przeprowadzania refaktoryzacji. Niewłaściwe utrzymywanie takich testów podczas ewolucji może pozwolić na przeoczenie błędów, które w przeciwnym razie zostałyby wykryte przez testy jednostkowe wykorzystujące instancje rzeczywistych klas. I odwrotnie, po prostu kpinie z jednej metody może wymagać znacznie mniej konfiguracji niż utworzenie całej prawdziwej klasy, a tym samym zmniejszyć potrzeby konserwacyjne.
Obiekty próbne muszą dokładnie modelować zachowanie obiektu, z którego szydzą, co może być trudne do osiągnięcia, jeśli obiekt, z którego się szydzi, pochodzi od innego programisty lub projektu lub jeśli nie został jeszcze napisany. Jeśli zachowanie nie jest prawidłowo modelowane, testy jednostkowe mogą zarejestrować przebieg, nawet jeśli awaria wystąpiłaby w czasie wykonywania w tych samych warunkach, w których wykonuje się test jednostkowy, co powoduje, że test jednostkowy jest niedokładny.
Zobacz też
Linki zewnętrzne
- Tim Mackinnon (8 września 2009). „Krótka historia makiety obiektów” . Mockobjects.com/.
- Test Doubles : część książki o wzorcach testów jednostkowych.
- Wszystko o symulowanych obiektach! Portal dotyczący makiety obiektów
- „Używanie próbnych obiektów do złożonych testów jednostkowych” . IBM DeveloperWorks. 16 października 2006 r. Zarchiwizowane od oryginału w dniu 4 maja 2007 r.
- Testy jednostkowe z próbnymi obiektami IBM developerWorks
- Mocki nie są stubsami ( Martin Fowler ) Artykuł o tworzeniu testów z obiektami Mock. Identyfikuje i porównuje „klasyczną” i „mockistowską” szkołę testowania. Porusza kwestie dotyczące wpływu na projekt i konserwację.