Testuję interfejs API REST. Powiedzmy, że zwraca strukturę JSON. Jakie jest najlepsze podejście do testowania serwera? Każdy krok testowy może się powieść tylko wtedy, gdy wszystkie poprzednie zakończyły się powodzeniem.
Struktura A: przetestuj wszystko na raz
- Test method 1:
- make server request
- assert http response code was 200
- assert returned file is not empty
- assert returned file has valid JSON syntax
- assert returned JSON contains key X
To wydaje się być najlepszym rozwiązaniem.
Zalety:
- Tylko jedno żądanie serwera
- Testuję zachowanie jako całość „Czy serwer zwraca JSON z kluczem X?”
Struktura B: stopniowo dodawaj potwierdzenia do każdego testu
- Test method 1:
- make server request
- assert http response code was 200
- Test method 2:
- make server request
- assert returned file is not empty
- Test method 3:
- make server request
- assert returned file has valid JSON syntax
- Test method 4:
- make server request
- assert returned JSON contains key X
W ten sposób zacząłem to robić i byłem przekonany, że tak powinno być, ponieważ każda metoda testuje tylko jedną rzecz, a to zapewnia lepszą separację. Ale teraz myślę, że ponieważ nie są to testy jednostkowe, moja separacja nie jest właściwa i powinienem przetestować zachowanie jako całość.
Struktura C: złóż zapytanie raz i uruchom osobne metody testowe na buforowaną odpowiedź
- make server request and cache it (allow read-only access)
- Test method 1:
- assert http response code was 200 on cached server request
- Test method 2:
- assert returned file is not empty on cached server request
- Test method 3:
- assert returned file has valid JSON syntax on cached server request
- Test method 4:
- assert returned JSON contains key X on cached server request
Zalety:
- Brak powtarzających się (drogich) żądań serwera
- Nadal ma metody testowe z jednym potwierdzeniem
Jakiej najbardziej sensownej struktury testowej użyć?
testing
acceptance-testing
mrplow
źródło
źródło
Odpowiedzi:
Najlepsze praktyki zawsze mają cel, przyczynę. Zawsze dobrze jest wziąć pod uwagę te powody w swoim projekcie - szczególnie, gdy próbujesz zdecydować, w jaki sposób i jak trudno zastosować te najlepsze praktyki.
W tym przypadku głównym powodem, dla którego każdy test jest jednym, jest to, że jeśli pierwsza nie powiedzie się, druga nie zostanie przetestowana. Ponieważ zbyt wielu opiniotwórców wydaje się odnosić korzyści z rozbijania wszystkiego na możliwie najmniejsze bity i zawijania jak największej liczby wzdęć, zrodziło to pomysł, że każdy test powinien zawierać jedno stwierdzenie.
Nie śledź tego na ślepo. Nawet jeśli każdy test powinien przetestować jedną rzecz, powinieneś zastanowić się, jak duża lub mała powinna być każda „rzecz”. Aby to zrobić, musisz pamiętać, dlaczego chcesz, aby każdy test testował jedną rzecz - aby się upewnić błąd w pierwszej rzeczy nie pozostawia drugiej rzeczy niesprawdzonej.
Musisz więc zadać sobie pytanie - czy naprawdę potrzebuję tutaj tej gwarancji?
Powiedzmy, że jest błąd w pierwszym przypadku testowym - kod odpowiedzi HTTP nie jest
200
. Więc zacznij hakować kod, dowiedz się, dlaczego nie otrzymałeś kodu odpowiedzi, i powinieneś rozwiązać problem. I co teraz?Jest jeszcze kilka rzeczy do rozważenia:
Zależności asercji
Wiem, że testy, które opisałeś, są tylko przykładem, a twoje rzeczywiste testy są prawdopodobnie bardziej skomplikowane - więc to, co powiem, może nie być tak ważne przy tak dużej sile w prawdziwych testach, ale nadal może być nieco skuteczne, więc może to rozważyć.
Jeśli masz usługę REST (lub dowolny inny protokół HTTP), która zwraca odpowiedzi w formacie JSON, zwykle piszesz prostą klasę klienta, która umożliwia korzystanie z metod REST, takich jak zwykłe metody zwracające zwykłe obiekty. Zakładając, że klient ma osobne testy, aby upewnić się, że działa, porzuciłbym pierwsze 3 twierdzenia i zatrzymałbym tylko 4!
Dlaczego?
Nie musisz więc uruchamiać wszystkich tych testów - po prostu uruchom czwarty test, a jeśli wystąpią jakiekolwiek błędy w pierwszych trzech próbach wykrycia, test zakończy się niepowodzeniem z odpowiednim wyjątkiem, zanim jeszcze uzyskasz rzeczywiste potwierdzenie.
Jak chcesz otrzymywać raporty?
Załóżmy, że nie otrzymujesz wiadomości e-mail z serwera testowego, ale zamiast tego dział kontroli jakości przeprowadza testy i powiadamia o niepowodzeniu testów.
Jack z QA puka do twoich drzwi. Mówi, że pierwsza metoda testowa zawiodła, a metoda REST zwróciła zły kod odpowiedzi. Podziękujesz mu i zaczynasz szukać przyczyny.
Potem przychodzi Jen z kontroli jakości i mówi, że trzecia metoda testowa zawiodła - metoda REST nie zwróciła poprawnego kodu JSON w treści odpowiedzi. Mówisz jej, że już patrzysz na tę metodę, i wierzysz, że to samo, co spowodowało, że zwrócił zły kod wyjścia, spowodowało również, że zwróciła coś, co nie jest prawidłowym JSON, i wygląda bardziej jak ślad stosu wyjątku.
Wracasz do pracy, ale potem przybywa Jim z kontroli jakości, mówiąc, że czwarta metoda testowa zawiodła i nie ma klucza X w odpowiedzi ...
Nie możesz nawet poszukać przyczyny, ponieważ trudno jest patrzeć na kod, gdy nie masz ekranu komputera. Gdyby Jim był wystarczająco szybki, mógłby umknąć w czasie ...
E-maile z serwera testowego są łatwiejsze do odrzucenia, ale nadal - czy nie wolałbyś po prostu POWIADOMIĆ RAZ, że coś jest nie tak z metodą testową, i sam przejrzeć odpowiednie dzienniki testów?
źródło
Jeśli możesz bezpiecznie założyć, że żądanie serwera z tymi samymi parametrami zachowa się zawsze tak samo, metoda B jest prawie bezcelowa - dlaczego miałbyś wywoływać czterokrotnie tę samą metodę, aby uzyskać te same dane odpowiedzi cztery razy, gdy jedno wywołanie wystarczy?
A jeśli nie możesz tego bezpiecznie założyć i chcesz włączyć go do testu, możesz lepiej uruchomić test A wiele razy.
Jedyną hipotetyczną sytuacją, w której widzę, gdzie B może przynieść korzyść, jest to, że środowisko testowania pozwala na włączanie i wyłączanie tylko jawnych metod testowania, a Ty oczekujesz konieczności wykonania tego na poszczególnych etapach testu.
Alternatywa C wydaje się łączyć A z jedną korzyścią, o której wspomniałem powyżej dla B. Jeśli twoja platforma testowa pozwala na taką strukturę kodu, bez większego obciążenia powyżej B, jest to wykonalne podejście. Dodaje to jednak dodatkową złożoność A, więc użyłbym jej tylko wtedy, gdybym chciał kiedykolwiek włączać i wyłączać poszczególne testy, w przeciwnym razie stosuję zasadę YAGNI i trzymam się najprostszego rozwiązania (A).
TLDR: zacznij od A, jeśli masz pewność, że zawsze chcesz, aby wszystkie aserty były uruchamiane w jednym teście, przejdź do C, jeśli zauważysz, że potrzebujesz łatwiejszej kontroli z zewnątrz w odniesieniu do poszczególnych asercji.
źródło
Jak każdy kod, unikaj przedwczesnej optymalizacji. Najpierw napisz swoje testy, aby były łatwe do odczytania i utrzymania. Gdy testy zaczną być zbyt wolne, zoptymalizuj je. W dość prostym przykładzie zarówno A, jak i B będą łatwe do odczytania i utrzymania, więc wybierz, który z nich chcesz, dopóki sprawy nie staną się zbyt wolne (struktura B) lub zbyt skomplikowane (struktura A).
Jeśli Twój serwer jest bezstanowy, możesz zoptymalizować, porównując rzeczywistą odpowiedź z oczekiwaną odpowiedzią, aby sprawdzić całą wiadomość za jednym razem. Oczywiście będzie to kosztem czytelności.
Jeśli twój serwer jest w stanie i musisz wykonać wiele powolnych wywołań interfejsu API, aby ustawić serwer w stanie do testu, wówczas podejmij inne podejście, inaczej uruchomienie testów może potrwać kilka minut. Na przykład możesz uruchomić aktualizację bazy danych, aby wstrzyknąć dane do testowej bazy danych, aby szybko uzyskać obiekt w odpowiednim stanie do testowania. Test jest szybki i czytelny, ale trudniejszy w utrzymaniu. Alternatywnie możesz być w stanie napisać fasadę przed interfejsem API, więc wiele wywołań interfejsu API stanie się pojedynczymi wywołaniami interfejsu API, które bardziej pasują do testowanego procesu biznesowego.
źródło
Testy nie powinny się dzielić - od zera unikasz wpływu jednego testu na drugi. Umożliwia to także uruchamianie testów w losowej kolejności.
Dlatego droga C nie powinna być akceptowana.
Pisząc dowolny kod (a może nawet tworząc cokolwiek innego), zawsze zadawaj sobie pytanie: „po co taka praktyka?”
Dlaczego mówimy, że powinny istnieć różne testy na wszystko?
Są dwa przypadki, gdy potrzebujesz tego:
Są dwa powody, dla których napotykasz te przypadki:
Jeśli z jakiegoś powodu nie może zadeklarować co najmniej jeden z tych powodów, aby mieć miejsce tylko ślepo wziąć struktura B .
W przeciwnym razie (mam nadzieję, że tutaj) wybrać A .
Możesz również zadać to pytanie na stronie Stackexchange zapewniania i testowania jakości oprogramowania .
źródło