Mam problem z testowaniem metody, która przesyła dokumenty do Amazon S3, ale myślę, że to pytanie dotyczy każdej nietrywialnej zależności API / zewnętrznej. Wymyśliłem tylko trzy potencjalne rozwiązania, ale żadne nie wydaje się zadowalające:
Uruchom kod, faktycznie prześlij dokument, sprawdź za pomocą interfejsu API AWS, czy został przesłany i usuń go na końcu testu. Spowoduje to, że test będzie bardzo wolny, będzie kosztował pieniądze za każdym razem, gdy zostanie przeprowadzony, i nie zawsze zwróci ten sam wynik.
Makieta S3. Jest to bardzo owłosione, ponieważ nie mam pojęcia o wnętrznościach tego obiektu i wydaje się niewłaściwe, ponieważ jest zbyt skomplikowane.
Upewnij się tylko, że MyObject.upload () jest wywoływany z właściwymi argumentami i ufaj, że poprawnie używam obiektu S3. Niepokoi mnie to, ponieważ nie ma sposobu, aby upewnić się, że poprawnie użyłem interfejsu API S3 z samych testów.
Sprawdziłem, jak Amazon testuje własny zestaw SDK, a oni robią sobie wszystko. Mają pomocnika o 200 liniach, który drwi. Nie wydaje mi się, żeby robienie tego samego było praktyczne.
Jak to rozwiązać?
Odpowiedzi:
Istnieją dwa problemy, na które musimy się tutaj zwrócić.
Po pierwsze, wydaje się, że patrzysz na wszystkie swoje testy z perspektywy testu jednostkowego. Testy jednostkowe są niezwykle cenne, ale nie są jedynymi rodzajami testów. Testy można w rzeczywistości podzielić na kilka różnych warstw, od bardzo szybkich testów jednostkowych przez mniej szybkie testy integracyjne do jeszcze wolniejszych testów akceptacyjnych . (Można wyłamać jeszcze więcej warstw, np . Testy funkcjonalne ).
Po drugie, łączysz wywołania kodu zewnętrznego z logiką biznesową, co stwarza wyzwania testowe i może sprawić, że Twój kod będzie bardziej kruchy.
Testy jednostkowe powinny być szybkie i powinny być przeprowadzane często. Wyśmiewanie zależności pomaga w szybkim działaniu tych testów, ale może potencjalnie wprowadzić dziury w zasięgu, jeśli zależność się zmieni, a próbka się nie zmieni. Kod może zostać uszkodzony, gdy testy będą nadal działać na zielono. Niektóre kpiące biblioteki ostrzegają o zmianie interfejsu zależności, inne nie.
Z drugiej strony testy integracyjne służą do testowania interakcji między komponentami, w tym bibliotekami stron trzecich. Na tym poziomie testowania nie należy używać prób, ponieważ chcemy zobaczyć, jak rzeczywisty obiekt współdziała ze sobą. Ponieważ używamy prawdziwych obiektów, testy te będą wolniejsze i nie będziemy uruchamiać ich tak często, jak nasze testy jednostkowe.
Testy akceptacyjne wyglądają na jeszcze wyższym poziomie, sprawdzając, czy wymagania dotyczące oprogramowania są spełnione. Testy te działają na całym, kompletnym systemie, który zostałby wdrożony. Po raz kolejny nie należy używać kpiny.
Jedną z wytycznych, które ludzie uznali za wartościową w odniesieniu do prób, jest nie kpić z typów, których nie posiadasz . Amazon jest właścicielem interfejsu API do S3, dzięki czemu mogą się upewnić, że pod nimi się nie zmieni. Ty natomiast nie masz tych zapewnień. Dlatego jeśli wyśmiejesz interfejs S3 API w testach, może on zmienić i zepsuć kod, podczas gdy wszystkie testy będą miały kolor zielony. Jak więc przeprowadzamy test jednostkowy kodu, który korzysta z bibliotek stron trzecich?
Cóż, my nie. Postępując zgodnie z wytycznymi, nie możemy kpić z obiektów, których nie jesteśmy właścicielami. Ale… jeśli posiadamy nasze bezpośrednie zależności, możemy wyśmiewać je. Ale jak? Tworzymy własne opakowanie dla interfejsu API S3. Możemy sprawić, że będzie wyglądać podobnie do S3 API, lub możemy dostosować go do naszych potrzeb (preferowane). Możemy nawet uczynić to trochę bardziej abstrakcyjnym, powiedz
PersistenceService
raczej niż anAmazonS3Bucket
.PersistenceService
byłby interfejs z metodami takimi jak#save(Thing)
i#fetch(ThingId)
, rodzajami metod, które chcielibyśmy zobaczyć (są to przykłady, możesz chcieć różnych metod). Możemy teraz zaimplementowaćPersistenceService
interfejs API S3 (powiedzmy aS3PersistenceService
), odsuwając go od naszego kodu wywołującego.Teraz kod, który wywołuje interfejs API S3. Musimy zastąpić te wywołania wywołaniami do
PersistenceService
obiektu. Używamy zastrzyku zależności, aby przekazać naszPersistenceService
obiekt. Ważne jest, aby nie prosić oS3PersistenceService
, ale prosić oPersistenceService
. To pozwala nam zamienić implementację podczas naszych testów.Cały kod, który używał bezpośrednio interfejsu API S3, teraz używa naszego
PersistenceService
, aS3PersistenceService
teraz wykonuje wszystkie wywołania interfejsu API S3. W naszych testach możemy wykpić sięPersistenceService
, ponieważ jesteśmy jego właścicielem, i użyć makiety, aby upewnić się, że nasz kod wykonuje prawidłowe wywołania. Ale teraz to pozostawia sposób testowaniaS3PersistenceService
. Ma taki sam problem jak poprzednio: nie możemy przetestować urządzenia bez wezwania zewnętrznego serwisu. Więc… nie testujemy tego jednostkowo. My mogli naśmiewać się z zależnościami S3 API, ale to dałoby nam trochę do żadnej dodatkowej pewności siebie. Zamiast tego musimy przetestować to na wyższym poziomie: testy integracyjne.Może to zabrzmieć trochę niepokojąco, mówiąc, że nie powinniśmy testować jednostkowo części naszego kodu, ale spójrzmy na to, co osiągnęliśmy. Wszędzie mieliśmy mnóstwo kodu, w którym nie mogliśmy przeprowadzić testu jednostkowego, który teraz można przetestować za pomocą
PersistenceService
. Mamy bałagan w bibliotece stron trzecich ograniczony do jednej klasy implementacji. Ta klasa powinna zapewniać niezbędną funkcjonalność do korzystania z interfejsu API, ale nie jest do niego dołączona żadna zewnętrzna logika biznesowa. Dlatego po napisaniu powinien być bardzo stabilny i nie powinien się bardzo zmieniać. Możemy polegać na wolniejszych testach, które nie uruchamiamy tak często, ponieważ kod jest stabilny.Następnym krokiem jest napisanie testów integracji
S3PersistenceService
. Powinny być one oddzielone według nazwy lub folderu, abyśmy mogli je uruchomić oddzielnie od naszych szybkich testów jednostkowych. Testy integracyjne mogą często wykorzystywać te same ramy testowe, co testy jednostkowe, jeśli kod jest wystarczająco informacyjny, więc nie musimy uczyć się nowego narzędzia. Rzeczywisty kod do testu integracji jest tym, co napiszesz dla Opcji 1.źródło
Musisz zrobić jedno i drugie.
Uruchamianie, przesyłanie i usuwanie jest testem integracyjnym. Łączy się z systemem zewnętrznym i dlatego można oczekiwać, że będzie działał wolno. Prawdopodobnie nie powinien być częścią każdej kompilacji wykonywanej lokalnie, ale powinien być częścią kompilacji CI lub kompilacji nocnej. To równoważy powolność tych testów i nadal zapewnia wartość automatycznego testowania.
Potrzebujesz także unittestów, które działają szybciej. Ponieważ ogólnie rzecz biorąc rozsądnie jest nie polegać zbytnio na systemie zewnętrznym (abyś mógł zamienić implementacje lub przełączyć się), prawdopodobnie powinieneś spróbować napisać prosty interfejs na S3, na którym można kodować. Wyśmiewaj ten interfejs w unittests, abyś mógł szybko uruchamiać unittests.
Pierwsze testy sprawdzają, czy kod rzeczywiście działa z S3, drugie testy, w których kod poprawnie wywołuje kod, który komunikuje się z S3.
źródło
Powiedziałbym, że zależy to od złożoności korzystania z interfejsu API .
Zdecydowanie musisz wykonać przynajmniej kilka testów, które faktycznie wywołują interfejs API S3 i potwierdzają, że działał on od końca do końca.
Zdecydowanie musisz także przeprowadzić dodatkowe testy, które tak naprawdę nie wywołują interfejsu API, abyś mógł odpowiednio przetestować własne oprogramowanie bez wywoływania interfejsu API przez cały czas.
Pozostaje pytanie: czy musisz wyśmiewać interfejs API?
Myślę, że to zależy od tego, jak dużo z tym zrobisz. Jeśli wykonujesz tylko jedną lub dwie proste czynności, nie sądzę, abyś musiał zadawać sobie tyle trudu, co makieta. Byłbym zadowolony po prostu sprawdzając, czy korzystam z funkcji i przeprowadzając testy na żywo.
Jeśli jednak korzystanie z niego jest bardziej złożone, z różnymi scenariuszami i różnymi zmiennymi, które mogą wpływać na wyniki, prawdopodobnie trzeba go wyszydzić, aby przeprowadzić dokładniejsze testy.
źródło
Dodając do poprzednich odpowiedzi, głównym pytaniem jest, czy (i jak) chcesz wyśmiewać interfejs API S3 do swoich testów.
Zamiast ręcznie wyśmiewać poszczególne odpowiedzi S3, możesz skorzystać z niektórych bardzo wyrafinowanych istniejących frameworków. Na przykład moto zapewnia funkcjonalność, która jest bardzo podobna do rzeczywistego API S3.
Możesz także spojrzeć na LocalStack , platformę, która łączy istniejące narzędzia i zapewnia w pełni funkcjonalne środowisko chmury lokalnej (w tym S3), które ułatwia testowanie integracji.
Chociaż niektóre z tych narzędzi są napisane w innych językach (Python), powinno być łatwo rozdzielić środowisko testowe w zewnętrznym procesie na podstawie testów, powiedzmy, Java / JUnit.
źródło