Pisząc testy jednostkowe, często używa się urządzeń: mało danych do przetestowania, więc możemy powiedzieć: 1. Zdobądź wszystkich klientów, którzy powinni dołączyć Willy Wonka. 2. Usuń klienta 3, a teraz zdobądź klientów nie powinien już zawierać Willy Wonka.
To dobrze w testach jednostkowych. Użyj setup / teardown, aby ponownie załadować urządzenia lub wycofać transakcję. Testowanie tworzy, aktualizuje i usuwa w ramach transakcji . Nowe dane tymczasowe trwają tylko przez czas trwania tego testu, a następnie są resetowane.
A co z oddzieleniem serwera REST od klienta REST?
Chcemy mieć pewność, że nasz klient REST nie tylko poprawnie odczytuje, ale również tworzy, aktualizuje i usuwa poprawnie.
Nie udało mi się znaleźć żadnych przykładów ani sugestii, jak to zrobić w przypadku zdalnego testowego serwera REST.
Zakładając, że mam testowy serwer REST obsługujący tylko urządzenia. Cały bezpaństwowy charakter HTTP oznacza, że trudno byłoby wysłać komunikat „POCZĄTEK TRANSAKCJI” i „TRANSAKCJA ROLLBACK” lub „RELOAD FIXTURES”, prawda?
Nie mogę być pierwszym, który chce to zrobić, więc mam wrażenie, że potrzebuję innego sposobu myślenia o tym.
Jakieś sugestie?
źródło
Odpowiedzi:
Systemy oprogramowania idealnie mają dobrze zdefiniowane granice systemu i interfejsy między nimi. Usługi REST są tego dobrym przykładem.
W tym celu, polecam przeciwko temu, co próbujesz zrobić.
Konkretnie:
Zamiast tego sugerowałbym:
Budowanie testów dla klienta REST, aby upewnić się, że zachowuje się on poprawnie, biorąc pod uwagę określone dane wejściowe i wyjściowe. Uwzględnij dobre (oczekiwane) i złe (nieoczekiwane) wartości.
Budowanie testów dla usługi REST (jeśli ją kontrolujesz), aby zachowywać się zgodnie z jej zamierzoną funkcją
Testy powinny znajdować się blisko ich problematycznej dziedziny, aby pomóc w projektowaniu i rozwijaniu tego, co ważne w tym kontekście
źródło
Pamiętaj o dwóch kątach:
źródło
Myślę, że sfałszowanie odpowiedzi serwera REST to najlepszy sposób na przetestowanie klienta.
Dla Ruby jest klejnot FakeWeb, którego możesz użyć do emitowania fałszywych odpowiedzi - https://github.com/chrisk/fakeweb .
Ponadto w JavaScript możesz użyć czegoś takiego jak Sinon.JS, co daje fałszywy serwer - http://sinonjs.org/docs/#fakeServer .
źródło
Jak powiedzieli inni, jeśli testujesz klienta, nie musisz sięgać aż do tworzenia, usuwania itp. Na serwerze. Często nie musisz nawet kpić z serwera. Naprawdę musisz tylko upewnić się, że wysyłasz właściwe żądania i poprawnie obsługujesz odpowiedzi, bez względu na to, czy jest napisane w Ruby, Python, PHP lub cokolwiek innego, w pewnym momencie twój klient prawdopodobnie użyje metody z biblioteki HTTP, aby zrobić żądanie i wystarczy wykpić tę metodę, sprawdzić, jak się nazywa, i zwrócić wynik testu.
Weźmy hipotetycznego klienta Python, który używa
urllib2
do wykonywania żądań. Prawdopodobnie masz jakąś metodę w kliencie, nazwijmy jąget()
, która ma w sobie wywołanieurllib2.Request()
. Naprawdę wystarczy kpić z połączenia z własną klasąget()
.Ten bardzo uproszczony przykład wykorzystuje bibliotekę Mock Pythona do testowania hipotetycznej
your.Client
klasy za pomocąget_object()
metody, która generuje poprawny adres URL, aby uzyskać coś z jakiegoś API. Aby złożyć żądanie, klient wywołujeget()
metodę z tym adresem URL. W tym przypadku metoda ta jest wyśmiewana (your.Client.get
„łatana”, aby była pod kontroląyour_mock
), a test sprawdza, czy zażądano właściwego punktu końcowego.Wyśmiewana metoda zwraca skonfigurowaną odpowiedź JSON (
your_mock.return_value
), którą klient musi obsłużyć, a użytkownik wykonałby dalsze stwierdzenia, aby sprawdzić, czy obsłużył oczekiwane dane w oczekiwany sposób.źródło
Opisujesz scenariusz testu integracji. Zazwyczaj są one nieco niewygodne w konfiguracji i burzeniu. Powoduje to, że biegają powoli i często są kruche.
Podejście do urządzeń jest równie niezręczne i niezdarne, ale jest to domyślny sposób, w jaki radzą sobie z tym niektóre frameworki, np. Rails, i jest już obsługiwany. Potrzebują abstrakcyjnego przypadku testowego lub czegoś podobnego, aby przygotować bazę danych z urządzeniami. (Uwaga na nietypowe nazewnictwo kategorii testowych w Railsach, testy jednostkowe z urządzeniami DB są ściśle mówiąc również testami integracyjnymi.)
Chciałbym zająć się twoim scenariuszem, aby zaakceptować specyficzną dla testu kontrolę nad stanem aplikacji API lub jej bazą danych. Możesz mieć dodatkowe punkty końcowe do instalacji i porzucenia, które są obecne tylko w środowisku testowym. Lub alternatywnie, rozmawiasz z bazą danych (lub czymkolwiek, czego używasz) z tyłu aplikacji / interfejsu API.
Jeśli uważasz, że to za dużo (w sensie nadmiernego) wysiłku, zastanów się, że podejście z urządzeniami do baz danych robi to samo: używając dodatkowych, specyficznych dla testu środków do manipulowania stanem bazy danych lub aplikacji.
Nie sądzę jednak, aby ta dyskusja miała związek z bezstanową naturą HTTP. HTTP jest bezstanowy, ale aplikacja zdecydowanie nie jest w większości przypadków. To brzmi trochę tak, jakbyś szukał surowości REST. Równie dobrze możesz mieć wszystkie zasoby, które można w pełni tworzyć, odczytywać i usuwać. W takim przypadku możesz po prostu przeprowadzić konfigurację i porzucić za pomocą zwykłych środków API. Często jednak nie robi się tego w praktyce, ponieważ nie chcesz uwzględniać niektórych operacji w biznesowym rozumieniu twojej aplikacji, przynajmniej poza środowiskiem testowym.
źródło
Łatka Małpy
W mojej pracy wykonujemy ATDD przy użyciu wychodzącego frameworka xUnit i łatania połączeń sieciowych między klientem a serwerem. W tej samej przestrzeni procesu ładujemy klienta, małpujemy łatanie połączenia sieciowego na górze kodu stosu serwera REST. Wszystkie połączenia są następnie wysyłane przez klienta, tak jak normalnie, a kod serwera otrzymuje żądania dokładnie tak, jak normalnie by się pojawiały.
Korzyści
Kompromisy
źródło