Automatyzacja testowania UI na iOS stała się tak łatwa, jak pisanie testów jednostkowych, odkąd Apple wprowadziło framework XCUI. W tym poście zamierzam opowiedzieć o tym, jak XCUI, w połączeniu z projektowaniem warstwowym, może pomóc łatwo zautomatyzować aplikacje, szczególnie te z wieloma niestandardowymi elementami UI. Jedną z aplikacji, w której zastosowaliśmy to rozwiązanie, jest VMware Boxer, aplikacja korporacyjna firmy VMware, która łączy w sobie trzy ważne funkcje – Email, Kalendarz i Kontakty. VMware Boxer wykorzystuje wiele typów elementów UI, od natywnego UITableView do wysoce niestandardowych elementów wizualnych.
Zakłada się, że czytelnicy mają podstawowe zrozumienie Xcode, Objective C, Swift, XCUI framework i ekosystemu rozwoju Apple w ogóle. Jeśli jesteś nowy w XCUI, powinieneś najpierw zacząć tutaj.
Jak każdy inny projekt automatyzacji UI, nasz zespół zaczął od pytania o to, którego frameworka automatyzacji użyć. Wcześniej używaliśmy SeeTest. Jednak uznaliśmy to za okazję do zrewidowania naszej strategii automatyzacji, biorąc pod uwagę nową, złożoną funkcjonalność dodaną w VMware Boxer, liczbę produktów w ekosystemie VMware oraz testy integracyjne pomiędzy tymi produktami. Poniżej przedstawiamy wybory, które rozważaliśmy-
1. Kontynuacja z SeeTest
2. Earl Grey
3. XCUI
O ile SeeTest był w stanie obsłużyć nasze natychmiastowe potrzeby w zakresie automatyzacji, istniało niezależne wyzwanie, z którym musieliśmy się zmierzyć. Wymagało to od nas zaadoptowania nowego stosu technologicznego. Wymagało to dodatkowych szkoleń dla programistów iOS oraz dedykowanych ekspertów do utrzymania systemu automatyzacji.
Co z Appium? Nie braliśmy pod uwagę Appium z tych samych powodów, które zostały wymienione powyżej dla SeeTest. Appium jest dobrym wyborem, jeśli mieliśmy aplikacje hybrydowe lub znaczący kod współdzielony między Androidem i iOS.
Earl Grey 1 był możliwym wyborem, biorąc pod uwagę, że pozwolił nam pozostać w Xcode i narzędziach programistycznych Apple i był oparty na XCTest. Automatyzacja Earl Grey 1 działa jednak w tym samym procesie, co testowana aplikacja. Z drugiej strony, automatyzacja oparta na frameworku XCUI firmy Apple działa w oddzielnym procesie niż testowana aplikacja. Jest to preferowane, ponieważ testowana aplikacja nie powinna być niczym więcej niż czarną skrzynką dla podmiotu (procesu automatyzacji lub użytkownika końcowego), który testuje jej UI.
Posiadaj proces automatyzacji (ten, który testuje) odizolowany od rzeczywistej testowanej aplikacji. Testowana aplikacja nie powinna być niczym więcej niż czarną skrzynką dla procesu automatyzacji.
Każde nowe narzędzie w ekosystemie Apple, które nie jest zgodne z podejściem Apple (np. Earl Grey 1) może zawieść bez ostrzeżenia. Takie podejście może wymagać wiele wysiłku, aby utrzymać, aby kontynuować pracę z nowszymi lub przyszłymi ofertami Apple.
Early Grey 2 dodał zdolność do interakcji z XCUI. Była to próba dostosowania się do XCUI, ale miała te znane problemy.
W końcu, XCUI był preferowanym wyborem. Dzięki temu deweloper będzie miał większą kontrolę nad automatyzacją i będzie bezpośrednim beneficjentem każdej innowacji w ekosystemie Apple.
Testowana aplikacja i moduł automatyzacji XCUI
Zanim przejdziemy do szczegółów, ważne jest, aby powtórzyć, że moduł automatyzacji używający XCUI działa jako niezależny proces od aplikacji, która jest testowana. Na początek dodaliśmy nowy moduł, który od tej pory będziemy nazywać modułem automatyzacji (AM). AM jest przestrzenią roboczą zawierającą kolekcję klas i struktur danych używanych do automatyzacji VMware Boxer przy użyciu XCUI.
Identyfikatory dostępności
Ważne jest, aby aplikacja była tworzona z myślą o jej testowalności. Jednym z obowiązków programisty jest zapewnienie, że każdy element interfejsu użytkownika, który jest narażony na użytkownika końcowego, ma ustawiony identyfikator dostępności podczas rozwoju. Identyfikator dostępności jest łącznikiem pomiędzy testowaną aplikacją a procesem automatyzacji XCUI.
Identyfikator dostępności jest łącznikiem pomiędzy testowaną aplikacją a procesem automatyzacji XCUI.
Wzorzec projektowy
Jak wspomniano wcześniej, VMware Boxer jest ogromną aplikacją. Wybór wzorca projektowego został dokonany z uwzględnieniem tego, że testy powinny być łatwe do zaimplementowania, łatwe w utrzymaniu, wielokrotnego użytku, solidne i skalowalne. Poniższa treść wyjaśnia warstwy architektury modułu XCUI Automation dla VMware Boxer:
Następujący rysunek przedstawia podstawowe elementy składowe:
Klasy testowe
Jest to warstwa, która posiada klasy posiadające metody testowe. Intencją tej warstwy jest posiadanie testów składających się z minimalnego kodu, który mówi tylko to, co jest testowane. Ponadto, programista implementujący testy musi myśleć tylko o wysokopoziomowym przepływie aplikacji wymaganym do przetestowania tego, co jest testowane. Reszta złożoności (np. jak nawigować do UI, gdzie pożądane testy mogą być wykonane) powinna być wyabstrahowana do warstw wielokrotnego użytku. Odwołaj się do poniższego obrazka, który pokazuje przykładową metodę testową wyjaśniającą powyższą intencję – kod testuje czy interfejs ustawień może pomóc w włączeniu/wyłączeniu funkcji lub czy posiada wymagane kontrolki przełączników.
Tak więc, programista piszący testy mógłby napisać kod, który jest tak prosty jak pseudo kod. W międzyczasie, jasne jest, że pewna logika powinna być wywoływana z następnej warstwy (Flows: wyjaśnione w następnej sekcji).
Klasy Flows
Flows reprezentują zbiór klas, które zapewniają funkcjonalności wymagane przez różne klasy Testów. Funkcjonalności mogą obejmować konfigurację aplikacji przed wykonaniem prawdziwego przypadku testowego lub nawigację do określonej części testowanej aplikacji. Większość z tych funkcjonalności jest wielokrotnego użytku i wymagana w wielu testach, np. powyższy przykładowy test wymaga, aby 1. aplikacja była uruchomiona i 2. Nawigujemy do ekranu ustawień kontrolera funkcji.
Więc, klasy Flow byłyby wywoływane z Testów i implementowałyby przepływy takie jak „Navigate to Settings” lub „Navigate to Feature Controller Settings”.
Klasy Ekranów
Klasy Ekranów są klasami, które mają odwzorowanie jeden do jednego do odpowiednich Kontrolerów Widoku. Kontroler widoku może być, na wysokim poziomie, postrzegany jako klasa posiadająca (w widoku zaplecza) UIControls i metody, które odpowiadają na interakcję użytkownika z tymi UIControls. Klasa Screen jest po prostu odwzorowaniem proxy kontrolera widoku. Poniższy rysunek pokazuje to odwzorowanie. W UI znajduje się komórka Initial View i kiedy użytkownik stuknie w tę komórkę, może wybrać, co powinno być oznaczone jako widok początkowy dla aplikacji. Poniższy rysunek pokazuje jak klasa Screen jest zaimplementowana w celu odwzorowania powyższego wymagania.
Pseudo kod dla tej klasy Screen wyglądałby następująco –
// The class models the SettingFormViewController for XCUI tests.public class SettingsFormScreen {
private static let navBarId = "Boxer.Settings.NavigationBar"
private lazy var featureControllerCell = boxerApp.application.tables.cells public func navigateToFeatureController() -> Bool {
return // tap on Cell with featureControllerCellId
}
}class AccessibilityIdentifiers: NSObject {// MARK: Settings Screenstatic let featureControllerCellId = "Boxer.Settings.FeatureControllerCell"
}
czym jest boxerApp w powyższym kodzie? W powyższym kodzie boxerApp reprezentuje jednostkę, która jest instancją klasy BoxerApp, która enkapsuluje testowaną aplikację i jej ekrany. Zostanie to wyjaśnione w następnej sekcji.
Powyższy kod modeluje SettingFormViewController z VMware Boxer. Konwencja użyta w nazewnictwie klasy polega na tym, że nazwa pochodzi od nazwy kontrolera widoku poprzez zastąpienie przyrostka ViewController przez Screen. Należy również zwrócić uwagę na klasę convenience, która posiada identyfikatory dostępności.
Identyfikator dostępności jest wspólnym łącznikiem pomiędzy testowaną aplikacją a procesem automatyzacji XCUI.
Putting it Together: VMware Boxer XCUI Automation Module
Moduł UITest testuje uruchomioną aplikację. Ważne jest, aby model aplikacji był zaprojektowany w taki sposób, aby jedna instancja testowanej aplikacji była pojedynczą jednostką. Oznacza to, że testowana aplikacja powinna być postrzegana jako kolekcja klas ekranów uczestniczących w przepływach biznesowych (kolekcja klas przepływów), które są wywoływane z testów (kolekcja klas) w oparciu o wymagania testu. Każda jednostka aplikacji powinna posiadać dokładnie jedną instancję każdej klasy Screen, która odpowiada jednemu kontrolerowi widoku.
Jak to osiągnąć?
Zestaw testów XCUITest może to osiągnąć poprzez enkapsulację instancji testowanej aplikacji (XCUIApplication) w jednej jednostce np. klasie BoxerApp, która posiada aplikację członkowską i posiada wszystkie ekrany dla tej aplikacji. Poniższy rysunek wyjaśnia tę enkapsulację
W związku z tym, przed uruchomieniem pakietu XCUITest, pierwszą rzeczą jaką zrobi jest stworzenie instancji modułu BoxerApp używając identyfikatora wiązki testowanej aplikacji. Poniższy rysunek to wyjaśnia
Ta instancja BoxerApp (jednostka enkapsulująca XCUIApplication i Screens) jest następnie przekazywana przez Tests::testMethod do Flows::flowMethod jako pierwszy parametr.
Flows::flowMethod z kolei wywołuje Screen::screenMethod i przekazuje BoxerApp, jeśli jest to wymagane.
W końcu interakcja z UI aplikacji odbywa się poprzez Screen::screenMethod.
Następny rysunek przedstawia powyższy projekt.
Wniosek
Pisanie testów XCUI może być uciążliwe i nie do opanowania, jeśli nie jest zrobione z planem. Mam nadzieję, że ten post dostarczył pomocnych wskazówek, jak myśleć o strukturze projektu automatyzacji w modularny, czysty, warstwowy sposób.
Co dalej?
Zamierzam poruszyć te tematy w serii opowiadań, które planuję:
XCUI : Część 2 – Interakcja z aplikacjami natywnymi w czysty sposób
XCUI : Część 3 -Jak XCUI runtime może wchodzić w interakcję z testowaną aplikacją w czysty sposób.
XCUI : Część 4 -Obsługa alertów systemowych.
XCUI : Część 5 -Obserwowanie postępu testów i dostęp do raportów oraz przechwytywanie zrzutów ekranu.
.