Urządzenia z systemem iOS wciąż stanowią znaczącą część rynku mobilnego, zgarniając aż 22 procent sprzedaży na całym świecie. Ponieważ wielu oddanych klientów wraca po nowe produkty Apple, istnieje również duże zapotrzebowanie na aplikacje iOS. W tym artykule przyjrzymy się zapewnieniu jakości aplikacji iOS, dążąc do wykorzystania najlepszych praktyk przy użyciu narzędzi Appium, Cucumber i Serenity.
Struktura
Model obiektowy strony jest jednym z najlepszych podejść do testowania, które inżynierowie QA mogą zastosować w projekcie automatyzacji testów. Jest to taki sposób strukturyzacji kodu w projekcie automatyzacji, który poprawia jakość i czytelność kodu, utrzymanie testów, a na dodatek jest to świetny sposób na uniknięcie chaosu. Podstawową ideą tego rozwiązania jest trzymanie wszystkich odniesień do elementów mobilnych i metod wykonujących na nich operacje w jednym pliku klasy dla każdej strony lub ekranu aplikacji (lub strony internetowej dla nie-natywnych aplikacji webowych).
Jakie są korzyści z tego podejścia, możesz zapytać? Po pierwsze, dzięki niemu automatyzacja jest naprawdę prosta. Polega to na znalezieniu elementów w naszej aplikacji iOS za pomocą inspektora, a następnie wykonaniu na nich operacji. Kolejną główną zaletą jest spójna struktura projektu, która pozwala każdemu na szybkie poruszanie się po nim.
Przyjrzyjrzyjmy się przykładowi aplikacji zawierającej przepisy kulinarne. Po uruchomieniu pokazuje ona domyślną książkę kucharską z podstawowymi przepisami, która będzie naszą pierwszą stroną. Stamtąd użytkownik może przejść do dowolnego dostępnego przepisu, zaznaczając tym samym drugą stronę. Ponadto, aplikacja pozwala również na przeglądanie innych książek kucharskich lub zakup książek premium, co czyni ją trzecią stroną, a co za tym idzie – plikiem obiektu strony.
Podobnie, powinniśmy stworzyć odpowiednie pliki definicji kroków. Nie jest to obowiązkowa praktyka, ale trzymanie wszystkich definicji kroków w jednym miejscu powoduje niepotrzebny chaos.
Podczas tworzenia stron i plików klas definicji kroków warto wybrać nazwy związane ze stroną (ekranem aplikacji), nad której zawartością będziemy pracować. Nazwanie tych plików po jakiejś funkcji lub scenariuszu może wydawać się słuszne na pierwszy rzut oka, ale w miarę rozrastania się projektu zauważymy coraz większy bałagan w jego strukturze. Przyjęcie konwencji nazewnictwa stron sprawia, że każdy zaangażowany w projekt może się z nim od razu zapoznać i błyskawicznie rozpocząć współpracę nad nim. Taka praktyka przyczynia się również do ponownego wykorzystania kodu – zarówno definicji kroków, jak i metod/funkcji.
W przeciwieństwie do wspomnianych plików definicji kroków, pliki cech Cucumbera powinny być nazwane po cechach, które weryfikują. Sprytne, czyż nie? I znowu, uporządkowanie ich w katalogi nazwane w odniesieniu do konkretnej dziedziny testowanej aplikacji sprawi, że struktura będzie bardziej sensowna.
Podstawową koncepcją Serenity jest bycie „żywą dokumentacją”. Dlatego też nadawanie scenariuszom testowym i plikom funkcji odpowiednich nazw pomaga zespołowi i interesariuszom lepiej zrozumieć raporty i cały projekt.
Kolejnym składnikiem rozszerzającym korzyści płynące z zastosowania Page Object Model w projekcie automatyzacji testów jest PageFactory. Jest to narzędzie, które pomaga zmniejszyć nakład pracy przy kodowaniu i w prosty sposób umieścić lokalizatory MobileElements w kodzie, wykorzystując notację @FindBy. Stamtąd znalezienie elementów dla Appium, aby wejść z nimi w interakcję w testach jest znacznie prostsze.
Assertion
Running tests via Appium can be very resource-consuming. Aby ułatwić pracę maszynie macOS wykonującej testy na urządzeniu z systemem iOS, upewnij się, że nie wykonujesz ciągłej asercji widoczności wszystkich obiektów na stronie. Ta praktyka znacznie zwiększa czas wykonywania testu, co zazwyczaj nie jest najbardziej pożądaną rzeczą.
Co więcej, kiedy rzeczywiście musisz sprawdzić, czy element jest widoczny, włączony, klikalny lub cokolwiek pomiędzy – staraj się unikać lokalizowania elementów mobilnych za pomocą Xpath. Wskazówka inspektora Appium ma ważny punkt! Powinieneś zrobić co możesz, aby przekonać zespół programistów do podjęcia dodatkowego wysiłku i przypisania unikalnych identyfikatorów i nazw do elementów w aplikacji. To nie tylko sprawi, że testowanie automatyzacji będzie łatwiejsze i szybsze, ale w konsekwencji sprawi, że Twoja praca jako testera będzie bardziej efektywna, co ostatecznie przełoży się na podniesienie ogólnej jakości produktu. I właśnie po to tu jesteśmy. Nie wspominając o tym, że utrzymanie testów (np. przełączanie się na różne lokalizatory, gdy jest to konieczne) stanie się o wiele przyjemniejsze.
Zrozumienie kroków
Inny aspekt tworzenia tego rodzaju projektu sprowadza się do wykorzystania Cucumbera i użycia języka Gherkin.
Gherkin implementuje proste podejście z notacją Given, When, Then z pomocą dodatkowych And i But, które wydają się dość łatwe w użyciu. Możesz napisać całkiem sporo, co chcesz w krokach testowych swoich plików funkcji. Ostatecznie wywołane metody będą wykonywać akcje.
Ale powodem używania podejścia Behavior Driven Development i samego Cucumbera jest umożliwienie osobom nietechnicznym zaangażowanym w projekt zrozumienie, co dzieje się w polu testów. Nie tylko to, pisanie scenariuszy testowych w sposób Given/When/Then może również działać na Twoją korzyść. Takie wysokopoziomowe opisy testów dostarczone przez klienta lub analityka biznesowego sprawią, że zaczniesz kodować w mgnieniu oka, pod warunkiem, że są one napisane poprawnie. Oto kilka pomocnych wskazówek:
Scenariusze testowe napisane w Gherkinie powinny skupiać się na zachowaniu aplikacji (stąd Behavior Driven Development).
A oto przykład tego, jak NIE pisać scenariuszy testowych w Gherkinie, dalej zgłębiając temat aplikacji typu cookbook:
Powyższy przykład ilustruje dwie złe praktyki, których powinniśmy unikać: Skupia się na implementacji zamiast na zachowaniu oraz używa twardo zakodowanych wartości zamiast pisać kroki testowe w taki sposób, aby umożliwić reużywalność poprzez zmianę wartości w ramach kroku.
Więc, poprawny scenariusz dotyczący zakupu książki kucharskiej w naszej przykładowej aplikacji powinien wyglądać następująco:
Inny przykład:
Zastosowanie tego podejścia oznacza mniej pracy przy tworzeniu i kodowaniu kroków testowych za każdym razem, gdy zmienia się implementacja danej cechy.
Oprócz głównej notacji Given/When/Then, Cucumber wspiera użycie kroków koniunkcyjnych. Użycie notacji kroków And i But sprawi, że kroki testowe będą bardziej ogólne i wielokrotnego użytku, co skutkuje pisaniem mniejszej ilości kodu i utrzymaniem porządku w projekcie. Oto podstawowy przykład:
Jeśli zakodujesz powyższy krok 'Given’ do zlokalizowania naszego elementu receptury poprzez wyszukanie jego nazwy, możesz go użyć ponownie wiele razy zmieniając tylko wartość ciągu znaków w kroku (pod warunkiem, że poprawnie zakodujesz później definicję kroku). Ponadto, krok 'And’ może być częścią każdego scenariusza testowego, który wymaga takiego działania.
Przykładając to wszystko do kupy
Po skonfigurowaniu projektu wykorzystującego praktyki opisane powyżej, najbardziej widoczną częścią używania Serenity są generowane raporty z testów. Po zaadoptowaniu znacznika @RunWith(CucumberWithSerenity.class) w pliku klasy TestRunner, uruchomienie zestawu testów spowoduje wygenerowanie przez Serenity zbiorczego raportu z wynikami testów, który może być przydatny w ocenie jakości testowanej aplikacji i przedstawieniu statusu produktu interesariuszom lub zespołowi programistów.
Appium, Cucumber, Serenity – Podsumowanie
Jak widać, koncepcja najlepszych praktyk w testowaniu automatyzacji może być podsumowana w trzech słowach: reużywalność, czytelność i wydajność. Wielokrotne użycie oznacza mniej kodowania, w konsekwencji zmniejszając czas potrzebny do ukończenia pracy. Czytelność poprawia zrozumienie, co jest kluczowe dla zapewnienia, że produkt robi to, co powinien robić. Wreszcie, wydajność oszczędza czas wykonania i poprawia stabilność. Wszystkie trzy czynniki przyczyniają się nie tylko do jakości projektu automatyzacji testów, ale mają znaczącą rolę w podnoszeniu ogólnej jakości dostarczanej aplikacji.