To, czego na froncie nie widać — czyli testowanie RESTful API.
API, zwane także Application Programming Interface, stanowi niezwykle istotny element we współczesnych aplikacjach komputerowych. To kluczowy składnik, który umożliwia skuteczną komunikację między różnymi modułami oprogramowania oraz zapewnia płynną wymianę danych między różnymi systemami. Aby zilustrować jego funkcję, można porównać je do roli kelnera w restauracji, działającego jako pośrednik między klientem (czyli nami) a serwerem (czyli kuchnią), z której pochodzą nasze zamówione dania. To narzędzie staje się kluczowym elementem wspomagającym efektywną interakcję między różnymi składnikami oprogramowania, co przekłada się na płynne funkcjonowanie aplikacji. Dzięki zastosowaniu API możliwe jest sprawniejsze dostarczanie usług oraz integracja różnych systemów, co stanowi istotny aspekt w dzisiejszym świecie technologii.
W ramach technologii API istnieje również coś, co określa się jako RESTful API. Jest to interfejs, który przestrzega kluczowych zasad projektowania, takich jak bezstanowość, jednolity interfejs oraz podział między klientem a serwerem. Dzięki tym zasadom, komunikacja między aplikacjami staje się bardziej efektywna i bezpieczna, podobnie jak w przypadku płynnej obsługi przez kelnera w restauracji. W artykule tym zgłębimy tajniki testowania API oraz korzyści płynące z jego odpowiedniego wykorzystania.
Testowanie REST API jest zaś jedną z form testowania backendu. Dziedzina ta jest bardziej wymagająca niż manualne klikanie we front-end, który to — dzięki graficznemu interfejsowi użytkownika — jest dużo bardziej intuicyjny dla początkującego testera dzięki znajomości tak witryn internetowych, jak i aplikacji mobilnych z własnego życia. Czy jednak warto przeszkolić testera w obsłudze zapytań backendowych oraz po co i jak testować API — na te pytania postaram się dzisiaj odpowiedzieć.
Czego nie widać, tego testerowi nie żal
Jednym z podstawowych powodów do wprowadzenia testowania back-endu jest typ modelu rozwoju oprogramowania. Bardzo często zespoły pracują w ujęciu iteracyjnym (np. Scrum) najpierw dostarczając kryteria akceptacji i design, później zaś prowadzona jest implementacja rozwiązań tak po stronie back-endu jak i front-endu. Nader często zdarza się, że w pierwszej kolejności tworzony jest back-end bądź jego implementacja jest wymagana do stworzenia strony front-endowej. Niekiedy zadania back-endowe są dostarczane szybciej niż front-endowe, bądź nie są z nią jeszcze połączone. W tym momencie można wkroczyć z testowaniem, dzięki czemu jesteśmy w stanie nie tylko stwierdzić, że aplikacja została poprawnie zaimplementowana i jest gotowa na przyjęcie interfejsu użytkownika, ale także oszczędzamy czas, nie czekając na sfinalizowanie zadań pozwalających nam na manualne sprawdzenie aplikacji przy użyciu tego właśnie interfejsu. Tutaj warto wspomnieć o takim terminie jak “Shift-left” testing. W tradycyjnych modelach kontroli jakości, testowanie zawsze przesuwane było w prawo w cyklu życia oprogramowania. Testy były uruchamiane głównie w późnych fazach projektowych.Na pierwszym miejscu stawiano zawsze definiowanie i implementację oprogramowania, gdzie kontrola jakości wchodziła na plan w samej końcówce cyklu wytwarzania oprogramowania. Generowało to wiele problemów jak np. późne wychwytywanie defektów wymagań, trudność w pokryciu białoskrzynkowym kodu, mniej czasu na naprawę błędów i tym podobne. Koszty usuwania defektów są tym większe, im później rozpoczynamy testowanie względem momentu rozpoczęcia projektu. Jak możemy się już domyślać, testy API możemy wdrożyć już na samym początku wytwarzania oprogramowania, dzięki czemu wykrycie defektów jest dużo szybsze, na mniej skomplikowanym produkcie, oraz dużo tańsze — jesteśmy w stanie dość łatwo i precyzyjnie wskazać błędne wymaganie, implementację bądź braki w logice biznesowej. Testy API mogą się później stać testami regresji, dzięki czemu ich wcześniejsza implementacja pozostawia długotrwały i pozytywny ślad w cyklu rozwoju oprogramowania.
Co ma wspólnego przestrzeń Metaverse z krypto-sztuką?
Dzieła, które możesz zaprezentować w przestrzeni Metaverse to po prostu pliki, skany i zasoby modeli 2D i 3D, które bezpośrednio możesz umieścić na takich platformach jak Spatial, Voxels, Decentraland lub AltspaceVR. Wirtualne galerie zbudowane na platformach metaverse, dokładnie takie jak Spatial wykorzystują istniejące już przestrzenie muzealne, często przygotowane wcześniej przez ich twórców w świecie 3D. Są to takie wirtualne krainy, które stają się centrami sztuki dla dzieł NFT i nowej generacji artystów wywodzących się z Metaverse. Spatial jest jednym z najbardziej znanych światów, w którym mamy możliwość znalezienia się w wirtualnej przestrzeni i interakcji z innymi ludźmi w postaci naszych ‘avatarów’. Awatar czyli trójwymiarowy model personifikujący naszą realną osobę. Jako fanatycy sztuki i fani technologii, zespół innowatorów platformy Spatial specjalizuje się we wszystkich odmianach wirtualnych sal konferencyjnych.
Oznacza to, że stworzenie własnej galerii VR na tej platformie jest nie tylko łatwe, ale także zoptymalizowane pod kątem najlepszych możliwych doświadczeń zmysłowych. Możesz nie tylko widzieć i rozmawiać z artystami i odczytywać ich ruchy dzięki technologii zaimplementowanej w okularach VR, czyli ‘hand tracking’, ale również dzięki technologii sal VR firmy Spatial możesz już teraz sprzedawać swoje dzieła sztuki przy pomocy tokenów NFT. Jeśli chodzi o rozpoczęcie pracy z galerią sztuki VR, platforma Spatial przygotowała konkretne przestrzenie i modele 3D, dzięki czemu jest to o wiele łatwiejsze niż na wielu innych, nie przystosowanych do tego celu specjalnie platformach. Jeśli jesteś nowy w świecie sal konferencyjnych i przestrzeni VR, zacznij od pobrania aplikacji Spatial, którą znajdziesz pod adresem https://www.spatial.io i utworzenia konta. Spatial czyni to szybko, łatwo i niedrogo dla artysty. Możesz albo iść z ich darmowym pakietem, który daje artystom większość narzędzi, których potrzebują, lub zapłacić 25 dolarów miesięcznie za “bardziej kontrolowane doświadczenie” i wsparcie technologiczne.
Jeśli już o regresji mowa, to warto wspomnieć o automatyzacji testów API. Oszczędza on dużo czasu w momencie, gdy aplikacja rozrasta się i kolejne iteracje dorzucają coraz to więcej funkcjonalności, które są albo oparte o początkowy kod, albo go modyfikują. W takim momencie kilkoma kliknięciami jesteśmy w stanie sprawdzić czy system jest nadal stabilny w środowisku deweloperskim przed wrzucaniem zmiany na środowisko przedprodukcyjne, gdzie koszt naprawy błędu rośnie. Innym znanym zastosowaniem automatycznych testów API są testy wydajnościowe i przeciążeniowe. Testy API muszą stworzyć sobie dane testowe przed sprawdzeniem ich poprawności i zachowań, dzięki czemu – są w stanie stworzyć niezliczoną liczbę operacji w krótkim czasie. Testerzy są w stanie zmierzyć czas tych operacji oraz zauważyć jak aplikacja radzi sobie w sytuacjach przeciążeniowych – czy jest zachowana odpowiednia skalowalność oraz wytrzymałość systemu. Sprawdza się to również jako test bezpieczeństwa systemu (w przypadku ataków DDOS). Wspomniane tworzenie danych testowych może również wesprzeć proces testowy na front-endzie – np. tworzenie użytkowników różnych krajów, z różnymi rolami oraz różną ilością danych jest czymś, co demotywuje testerów manualnych i jest wielkim nakładem pracy, a jest przydatne w przypadku testowania zmian lokalizacyjnych lub wydajności systemu front-endowego w przypadku renderowania dużej ilości danych back-endowych.
Interfejs użytkownika? A komu to potrzebne!
Zdarza się, że aplikacja lub projekt nie posiadają GUI lub nie potrzebują go do działania. W takim wypadku testowanie aplikacji odbywa się wyłącznie na back-endzie. Wiele systemów pracuje już od lat na starych technologiach i tzw. legacy-code, który z biegiem czasu staje się coraz bardziej kosztowny w utrzymaniu i naprawie. Trudność w pozyskiwaniu specjalistów dla danych technologii staje się uporczywa, zaś widełki płacowe stają się piekielnie wysokie. W takim wypadku dokonuje się migracji danych na nowy system, bądź też refactoringu lub też przepisania kodu na nowe technologie, często – z zachowaniem poprzedniego UI aplikacji. Wtedy też testowanie przebiega tylko na linii testowania kodu, baz danych oraz właśnie API. Programiści sprawdzają własny kod testami jednostkowymi (eng. unit tests), tworzą zaślepki dla testów integracyjnych (eng. integration tests), zaś rolą testera jest stworzenie zestawu testów akceptacyjnych, jak już wspomniałem – mogących stać się bazą testów regresyjnych. Testy te są uruchamiane przed każdym wypuszczeniem nowej zmiany na środowisko deweloperskie czy przedprodukcyjne oraz produkcyjne. Pomóc w tym może proces CI/CD, eng. Continuous Integration/Continuous Deployment. Aplikacje takie jak GitHub czy Azure Pipelines mogą wspomóc automatyzację wypuszczania zmian na środowisko tylko i wyłącznie jeśli wyniki testów okażą się pozytywne. Taki schemat działania pozwala na zminimalizowanie ryzyka przepuszczenia błędów na środowiska testowe i później produkcyjne. Pozostaje jeszcze kwestia bezpieczeństwa aplikacji jak i użytkownika. Wyobraźmy sobie sytuację, w której brakuje implementacji walidatorów na stronie frontowe. Użytkownik jest w stanie wprowadzić wszelkie rodzaje symboli tak w nazwę użytkownika, jak i hasło, bio, zainteresowania. Mógłby również – nawet przypadkowo – nie wprowadzić niczego w dane pole, a przez brak front-endowej walidacji dane te (lub ich brak) zostaną przesłane dalej do serwera i zapisane na bazie danych. W tym momencie możemy natknąć się na kilka problemów, zaczynając od pustych danych, które mogą wywołać przeróżne błędy kodu i zamknięcie się aplikacji. Jednym z tych błędów to ArgumentNullException lub IsNullOrWhiteSpace. Używając walidatorów na back-endzie jesteśmy w stanie wyłapać puste pola, które po wysłaniu zapytania – nie dopuszczą do przesłania danej dalej, a poinformują klienta kodem 400 – Bad Request, że czegoś brakuje. Oczywiście użytkownik końcowy powinien być poinformowany o tym błędzie w sposób bardziej przyjazny i zrozumiały, typu “Wprowadź przynajmniej trzy znaki w polu tytułowym aby wysłać formularz”. Błąd ten jednak powinien zostać wyłapany przez front-end, back-end jest tutaj bezpiecznikiem, który nie dopuszcza błędnych danych dalej w momencie, gdy walidacje front-endowe nie zadziałają, przesył danych zostanie przerwany lub zmodyfikowany (np. w wyniku zaniku sieci, lub przez działanie stron trzecich). Inną kwestią są błędne dane, które mogą powodować problemy w trakcie ich przyjmowania przez serwer. Podanie liter w miejsce liczb, przecinka w miejsce kropki lub znaku specjalnego może spowodować błędy parsowania danych. Prostym przykładem może być oznaczanie znajomych w wiadomościach lub postach przy użyciu symbolu ‘@’ – jeśli zamiast nazwy użytkownika podamy jeden ze znaków specjalnych ‘!?<>{}’ możemy sprawić, że system zachowa się nieprzewidywalnie – chyba, że te wyjątki są obsługiwane przez testy API (lub kodu).
Bezpieczeństwo przede wszystkim
Strony trzecie, czyli osoby, instytucje lub firmy mogą spróbować zaszkodzić naszej aplikacji. Warto w takim momencie wykonać testy penetracyjne API, aby mieć pewność, że nasza aplikacja zachowa się stabilnie w każdej sytuacji. Istnieje wiele znanych przykładów łamania bezpieczeństwa API. Oto kilka z nich:.
- Broken User Authentication – brak wymaganej autoryzacji użytkownika. Gdy system nie wymaga odpowiedniego loginu i hasła, atakujący mogą uzyskać dostęp do chronionych zawartości.
- Broken Object Level Authorization – niektóre wrażliwe dane mogą być niewłaściwie wyeksponowane w odpowiedzi na zapytanie. Może być to rezultatem błędu po stronie komponentu, przez co opieramy się bardziej na numerze identyfikacyjnym obiektu aniżeli jego statusie.
- Lack of Resources & Rate Limiting – ta podatność pojawia się gdy API nie stosuje żadnych restrykcji co do ilości zapytań, które mogą być wysłane przez specyficznego klienta. Może to zostać wykorzystane przez atakujących mogących wysłać nadmiarową ilość zapytań, przez co dany zasób może zostać wyczerpany, co uniemożliwi jego użycie przez innych klientów.
- Injection – możemy próbować wstrzykiwać do systemu (poprzez metodę PUT) dane, które nie powinny się tam znaleźć. Jako rezultat możemy uzyskać nieprzewidzianą odpowiedź serwera, która może zawierać wrażliwe dane pozwalające nam na wykonanie rekonesansu systemu, lub nawet na jego przejęcie.
Często istnieje osobna specjalizacja testerska, tzw. Pentester, czyli etyczny haker. Osoba ta zatrudniona w firmie dokonuje audytów bezpieczeństwa, często i gęsto wykorzystując zapytania API do próby wdarcia się do systemu, spowolnienia go lub wywołania awarii. Warto spojrzeć na narzędzia do testowania API, które umożliwiają podejrzenie zapytań tak na produkcji, jak w środowisku testerskim.
Każdy może zostać listonoszem
Pierwszą z aplikacji wspomagających testy REST API którą wymienię jest Postman. Jest to dość popularne narzędzie wykorzystywane do tworzenia kolekcji zapytań i do ich egzekucji, testów manualnych jak i automatyzacji. W momencie gdy stworzymy potrzebne kolekcje, będziemy mogli udostępnić je, wraz z wynikami naszej pracy, innym użytkownikom w naszym zespole. Kolekcja to grupa zapytań do API, która pozwala na ich zapisanie i użycie w przyszłości. Często grupujemy zapytania wg. różnych kategorii, jak np. tworzenie, edycja czy listowanie użytkowników, zarządzanie grupami, do których dani użytkownicy mogą być przydzieleni oraz lista notyfikacji, które dani użytkownicy otrzymali, bądź wysłali. Istnieją również proste narzędzia automatyzujące wykorzystywanie zasobów naszej aplikacji. Zakładka “Tests” może być wykorzystana nie tylko do asercji odpowiedzi serwera (jak kody statusu, czas odpowiedzi, typ odpowiedzi bądź zawartość wymaganych danych), ale i automatyzację tworzenia zmiennych kolekcji lub środowiska. Dzięki temu, gdy stworzymy zasób o danym ID, jesteśmy w stanie wykorzystać go przy następnym zapytaniu, który może go spróbować odczytać, zaktualizować lub usunąć. Możliwość egzekucji całych kolekcji z użyciem narzędzia Newman lub skonfigurowanie CI/CD z użyciem zewnętrznych narzędzi takich jak Jenkins, Bitbucket, Gitlab, Github i wiele innych. Drugim narzędziem jest Charles Proxy. Jest to narzędzie podobne do Chrome Dev Tools,czyli służące do przechwytywania ruchu HTTP i HTTPS, jednak bardziej przejrzystym i umożliwiającym jedną bardzo ważną rzecz – monitorowanie ruchu sieciowego przekierowanego z telefonów komórkowych. Charles umożliwia podgląd endpointów, a także wysyłanych zapytań i otrzymywanych odpowiedzi na żywo w trakcie korzystania z aplikacji. Możemy dzięki temu przeglądać dane strukturalnie zapytań a także stawiać tzw. “Breakpoint”, który w momencie kiedy aplikacja natrafi na dane zapytanie, pozwoli przejrzeć jego zawartość lub zmodyfikować zapytanie i wysłać je ponownie. Charles może mieć również zastosowanie jeżeli chodzi o modyfikowanie kodu odpowiedzi, co umożliwia sprawdzenie zachowania aplikacji przy kodzie odpowiedzi, który jest nieoczekiwany. Network throttling, znany z Chrome Dev Tools jest również obecny w Charles Proxy. Jest to opcja pozwalająca nam ustawić parametry połączenia internetowego. Aplikacje mogą się zachować w nieprzewidywalny sposób, gdy ograniczymy przepustowość naszego łącza – czasy odpowiedzi endpointów zazwyczaj są dość krótkie (200-500 ms), zatem przy przedłużających się czasach odpowiedzi możemy napotkać błędy związane z przekroczeniem czasu odpowiedzi. Z drugiej strony – dzięki temu jesteśmy w stanie prześledzić ekrany ładowania aplikacji i sprawdzić, czy nie powstają żadne artefakty. Ostatnim miejscem, gdzie możemy wprowadzić testy API to kod aplikacji. Testy integracyjne i akceptacyjne mogą być wywoływane na zasadzie wspomnianego już wcześniej CI/CD i z zaślepkami, i na prawdziwej bazie danych. Testy te jednak wymagają dużo większej wiedzy programistycznej, i znajomości konkretnego języka programowania – zależności od technologii w której jest rozwijany projekt. Rynek poszukuje coraz większej ilości testerów ze znajomością Javy, Pythona, C++ czy C#, aby wspomogli proces testingowy nie tylko manualnie, ale i – lub tylko i wyłącznie – automatyzacją.
Testy API są jednym z ważniejszych, obok testów kodu i baz danych, testów back-endu. Wdrożenie ich już w początkowej fazie projektu oszczędza czas na dewelopment oraz gwarantuje większą stabilność i bezpieczeństwo aplikacji. Narzędzia do testów mają dość niski próg wejścia (nie wymagają umiejętności programowania), dzięki czemu łatwo jest wdrożyć mniej doświadczonego testera. Jednym z ukrytych plusów jest również zdywersyfikowanie i ułatwienie pracy testera, który to dzięki użyciu narzędzi do testów API nie tylko nie popada w monotonię pracy, ale i jest w stanie niskim wysiłkiem stworzyć dane testowe przy użyciu automatyzacji. Myślę, że łatwo jest udowodnić korzyści płynące z wdrożenia testów API w trakcie cyklu wytwarzania oprogramowania, płynące nie tylko w stronę projektu, ale i w stronę zaangażowanych w niego pracowników.