Testowanie REST API może wydawać się skomplikowane, ale odpowiednie testy mogą zaoszczędzić godziny (jeśli nie dni) żmudnego debugowania i sprawić, że wdrażanie nowych funkcji będzie przebiegać gładko. Odpowiednie podejście pozwala wykryć potencjalne problemy już na wczesnym etapie, minimalizując ryzyko późniejszych komplikacji. W poniższym artykule przyjrzymy się, jakie elementy warto uwzględnić, by upewnić się, że testowanie API jest skuteczne.
Jeśli potrzebujesz odświeżyć sobie wiedzę z zakresu podstaw testowania REST API, polecam zapoznać się z naszym mini-kursem dostępnym tutaj.
1. Czym testować API?
Najpopularniejszym narzędziem jest Postman. Postman umożliwia wysyłanie zapytań HTTP do wybranych endpointów API, a następnie analizowanie odpowiedzi zwracanych przez serwer. Można w nim łatwo testować, czy API działa zgodnie z założeniami i symulować różne scenariusze użytkownika. Narzędzie posiada także możliwość organizowania zapytań w kolekcje, co ułatwia zarządzanie nimi oraz wspiera współpracę zespołową, pozwalając na udostępnianie testów innym członkom zespołu.
Jeśli ktoś chciałby automatyzować testy API, dobrym wyborem może być biblioteka Rest Assured. Jest to popularne narzędzie przeznaczone do automatyzacji testów API w Javie, które pozwala na tworzenie skryptów testujących działanie interfejsów RESTful. Dzięki Rest Assured można pisać czytelne i elastyczne testy API, które integrują się z popularnymi frameworkami testowymi, takimi jak JUnit czy TestNG. Narzędzie to oferuje przyjazną składnię DSL, ułatwiającą definiowanie zapytań HTTP oraz weryfikację odpowiedzi serwera.
2. Jak testować API?
Testując API, łatwo wpaść w pułapkę sprawdzania jedynie scenariuszy pozytywnych. Chodzi tutaj o sytuację, kiedy skupiamy się tylko na przypadkach, w których wszystkie parametry i dane wejściowe są poprawne, a odpowiedzi serwera spełniają oczekiwania. W takich testach API działa zgodnie z dokumentacją, co daje poczucie stabilności, ale pomija ważne aspekty, jak zachowanie aplikacji przy błędnych lub niepełnych danych, nietypowych sytuacjach czy próbach nieautoryzowanego dostępu. Brak negatywnych scenariuszy może prowadzić do niedoszacowania potencjalnych problemów, które użytkownicy mogą napotkać w realnych warunkach.
Jakie scenariusze powinniśmy w takim razie zakładać? Poniżej znajduje się lista typów testów, którą ja stosuję podczas weryfikacji każdego API:
Jak wspomniano już wyżej, scenariusze pozytywne
Na przykład – mamy przetestować dodawanie nowego użytkownika. W tym celu wysyłamy request POST pod endpoint /api/users
. Treść żądania będzie wyglądała tak jak poniżej:
{
"name": "Jan Kowalski",
"email": "jkowalski@example.com"
}
Dane są poprawne (bo przecież zależy nam tutaj na tym, by test zakończył się sukcesem). Powinniśmy otrzymać kod odpowiedzi 201 i zwróconą treść z potwierdzeniem danych użytkownika, na przykład:
{
"id": 103,
"name": "Jan Kowalski",
"email": "jkowalski@example.com"
}
Operacja zakończona sukcesem!
Scenariusze negatywne
Ale jak już napisałem wyżej, klienci nie płacą nam tylko i wyłącznie za testowanie scenariuszy, które nie zakładają problemów które mogą się pojawić po drodze. Przykład -tym razem wyślijmy to żądanie bez e-maila nowego użytkownika:
{
"name": "Jan Kowalski"
}
Oczywiście powyższe żądanie jest niepoprawne – nie zawiera jednego wymaganego pola, którym jest adres e-mail użytkownika. Tym samym oczekujemy tutaj błędu. Powinniśmy otrzymać kod HTTP wskazujący na błędne żądanie (400 Bad Request), a użytkownik nie powinien zostać utworzony . Dodatkowo, serwer powinien zwrócić informację o błędzie, na przykład taką jak poniżej:
{
"error": "Email is required"
}
Taki test potwierdza, że API prawidłowo waliduje dane wejściowe i nie pozwala na utworzenie użytkownika bez kluczowych informacji.
Scenariusze destrukcyjne
W naszym zbiorze testów powinniśmy jeszcze uwzględnić tzw. scenariusz destrukcyjny, czyli rodzaj testu negatywnego, który sprawdza, jak API radzi sobie z ekstremalnie niepoprawnymi lub złośliwymi danymi. Przykład – wyślijmy request POST pod nasz endpoint /api/users
:
{
"name": "Jan Kowalski",
"email": "<script>alert('Hacked');</script>"
}
W powyższym przykładzie, pole „email” zawiera złośliwy kod zamiast prawidłowego adresu e-mail. API powinno odpowiedzieć kodem statusu 400 (Bad Request) lub innym kodem błędu, bez wykonania złośliwego kodu. Powinniśmy także otrzymać odpowiedź z informacją o błędzie.
Scenariusze brzegowe
Ten rodzaj testów (zwany także testami granicznymi) sprawdza, jak API reaguje na wartości graniczne dla danych wejściowych. Przykładem może być testowanie minimalnej i maksymalnej długości pola tekstowego.
W naszym przykładzie tworzenia nowego użytkownika możemy założyć, że istnieje maksymalna dopuszczalna liczba znaków dla imienia i nazwiska – niech to będzie 50 znaków. W tym przypadku powinniśmy sprawdzić przypadki :
- Co się stanie, kiedy wyślemy dane wejściowe z polem
name
o długości dokładnie 50 znaków - co się stanie przy 51 znakach i 49 znakach
- próba wysłania żądania z pustym polem (0 znaków)
- bardzo dużą liczbę, np 1000 znaków
- znaki specjalne np. @#$%^&*, by sprawdzić czy API akceptuje lub odrzuca pole
name
zawierające takie znaki - początek lub koniec z białymi znakami (np. „ Jan Kowalski „) by sprawdzić czy backend prawidłowo akceptuje / przycina spacje
i tak dalej.
Scenariusze integracyjne
Czym może być scenariusz integracyjny? Wyobraźmy sobie, że tworzymy nowego użytkownika za pomocą endpointa /api/users
(scenariusz pozytywny). Jednak pójdźmy o krok dalej – załóżmy, że nasz scenariusz zakłada nie tylko utworzenie użytkownika, ale także sprawdzenie jego uprawnień z użyciem endpointa /api/permissions
.
Czyli – musimy utworzyć nowego użytkownika i otrzymać informację z jego ID:
{
"id": 103,
"name": "Jan Kowalski",
"email": "jkowalski@example.com"
}
Następnie wysyłamy request POST /api/permissions
używając do tego ID utworzonego użytkownika. Chcemy przypisać mu rolę np. „user”:
{
"userId": 103,
"role": "user"
}
Otrzymujemy odpowiedź:
{
"userId": 103,
"role": "user",
"status": "assigned"
}
Taki test sprawdza, czy poszczególne komponenty aplikacji poprawnie ze sobą współpracują.
Autoryzacja i autentykacja
Na początek wyjaśnienie, czym różnią się te dwa terminy. Autentykacja polega na sprawdzeniu tożsamości użytkownika, który próbuje uzyskać dostęp do zasobów. Autoryzacja sprawdza, czy uwierzytelniony użytkownik ma odpowiednie uprawnienia do konkretnego zasobu. Warto przyjrzeć się obu tym elementom, testując API pod kątem ochrony dostępu do zasobów.
Jak testować autentykację? Upewnij się, że poprawne dane logowania, np. prawidłowy token, pozwalają na dostęp do zasobów. Sprawdź także, co się stanie, gdy podasz niepoprawne dane autentykacyjne, takie jak nieprawidłowy login, hasło, token JWT lub przeterminowany token. API powinno zwrócić odpowiednie błędy, jak np. kod 401 Unauthorized.
W przypadkach, gdy API obsługuje różne role (np. użytkownik standardowy i administrator), upewnij się, że każdy użytkownik ma dostęp jedynie do zasobów, do których powinien mieć uprawnienia – tak sprawdzisz autoryzację.
3. Co dokładnie sprawdzać?
Kiedy testuję REST API, skupiam się na następujących aspektach danego API:
Kody odpowiedzi
Na początek rzecz oczywista, czyli poprawność kodów odpowiedzi. Powinniśmy weryfikować, czy po wysłaniu żądania do serwera, zwracany kod statusu HTTP jest zgodny z oczekiwaniami. Status ten informuje, czy żądanie zostało przetworzone pomyślnie, czy wystąpił jakiś problem.
Oto przykłady:
- Wysyłamy request typu
GET
pod/products/123
. W odpowiedzi powinniśmy dostać status 200 (OK), jeśli ten produkt istnieje. Kod 200 oznacza, że żądanie zakończyło się sukcesem - Z kolei jeśli wyślemy request GET pod ID nieistniejącego produktu, np. pod /products/9999, serwer powinien zwrócić kod 404, sugerując, że żądany zasób nie jest dostępny
- Gdy zasoby są chronione i wymagają uwierzytelnienia, możemy przetestowa. W przypadku zapytania GET /user/account wysłanego bez poprawnego tokena autoryzacyjnego, API powinno odpowiedzieć kodem 401, co sugeruje brak uprawnień do dostępu
Generalnie zasada jest taka – wysyłamy żądanie i sprawdzamy, czy kod odpowiedzi serwera jest poprawny. Pamiętamy o tym, by nie sprawdzać jedynie pozytywnych przypadków testowych. Przykładowo, warto sprawdzić, co się stanie, gdy żądanie jest niepoprawnie sformułowane lub gdy użytkownik nie ma odpowiednich uprawnień.
Struktury odpowiedzi
Struktura i zawartość odpowiedzi (JSON schema) odnosi się do tego, czy odpowiedź API ma prawidłową strukturę i zawiera wszystkie oczekiwane pola o odpowiednich typach danych. Czemu się to testuje? Po to, by upewnić się, że odpowiedzi API są zgodne z ustalonym schematem, co pomaga w unikaniu błędów po stronie klienta, które mogą wystąpić, gdy odpowiedź nie jest taka, jak oczekiwano.
Na przykład – załóżmy, że API zwraca dane użytkownika w formacie JSON. Oczekiwany schemat odpowiedzi może wyglądać tak:
{
"id": 103,
"name": "Jan Kowalski",
"email": "jkowalski@example.com",
"role": "user
}
W teście JSON schema sprawdzamy, czy odpowiedź zawiera wszystkie wymagane pola (id
, name
, email
, role
) i czy mają one odpowiednie typy danych (id jako liczba całkowita, reszta pól jako jako łańcuchy znaków). Brak któregokolwiek z tych pól lub błędny typ danych (np. id
jako ciąg znaków zamiast liczby) powinien skutkować błędem testu.
Czasy odpowiedzi
Testy te polegają na pomiarze czasu, jaki zajmuje API, aby odpowiedzieć na żądanie od momentu jego wysłania do otrzymania pełnej odpowiedzi. Innymi słowy, mierzymy czas w jakim dostaniemy odpowiedź z serwera – może to być dowolna wartość, mierzona najczęściej w milisekundach, np. 250 ms.
Wyniki są porównywane z wcześniej ustalonymi oczekiwaniami, które mogą na przykład określać, że czas odpowiedzi nie powinien przekraczać 200 ms.

Nagłówki
Nagłówki HTTP określają dodatkowe informacje o żądaniu lub odpowiedzi, takie jak typ zawartości, dane uwierzytelniające, informacje o cache’owaniu i wiele innych. Nieodpowiednie lub brakujące nagłówki mogą prowadzić do błędnego przetwarzania danych, problemów z bezpieczeństwem, a także do niepotrzebnego obciążenia serwera lub klienta.
Najczęściej testowane nagłówki to:
- Content-Type – określa typ danych w odpowiedzi, np.
application/json
- Authorization – zawiera dane uwierzytelniające (np. tokeny JWT), które potwierdzają tożsamość użytkownika lub uprawnienia do uzyskania dostępu do zasobów