Testy UI w technologii Continuous Integration – Jenkins + Fastlane + Appium

Testy UI to przydatne narzędzie zwłaszcza wtedy gdy mamy już duża aplikacje i przed opublikowaniem nowej wersji zależy nam na przeprowadzeniu testów regresyjnych.

Z naszej praktyki wynika że dość łatwo jest spowodować sytuację, że nowo napisany fragment kodu powoduje błędy w działaniu wcześniej napisanych modułów. Teoretycznie takie sytuacje nie powinny mieć miejsca, ale jesteśmy tylko ludźmi i popełniamy błędy, a testy UI są jedną z kilku warstw testowania (obok testów jednostkowych i integracyjnych) przed uznaniem, że kolejna wersja aplikacji spełnia standardy jakości. Oczywiście można takie testy przeprowadzać manualnie, ale powoduje to zużycie o wiele większej ilości czasu, zwłaszcza gdy mamy do czynienia z aplikacja wieloplatformową (IOS i Android).

O wiele lepszym rozwiązaniem wydaje się więc poświęcenie tego czasu na napisanie testów UI, które w kolejnych update-ach aplikacji niemal bez straty czasu na ponowne testy załatwią ten problem. Testy wykonują te same czynności które wykonałby tester sprawdzając poprawność działania newralgicznych miejsc aplikacji.

Symulatory testowe

W poniższym artykule skupię się na omówieniu testów UI w odniesieniu do platformy IOS. Podane szczegóły techniczne realizacji różnią się nieco dla platformy Android i IOS. Głównym celem było stworzenie systemu potrafiącego przetestować obydwie te platformy, a opisane poniżej techniki tyczą się tylko jednej – IOS.

Testować będziemy na symulatorach – możliwe jest podpięcie fizycznych urządzeń i testowanie na nich, ale opcja z symulatorami na pewno jest prostsza do realizacji – możemy przetestować naszą aplikację na dowolnym urządzeniu Apple z praktycznie dowolną zainstalowana wersją systemu IOS. W przypadku testowania na fizycznych urządzeniach może to być nieco kłopotliwe (ale wykonalne 🙂 )

Narzędzia

Zakładam, że czytelnik ma podstawowa wiedzę o każdym z narzędzi opisanych w artykule, ale tak czy tak dorzucę parę linków i krótkie opisy poszczególnych elementów układanki :). Wszystkie opisane narzędzia mamy zainstalowane na wydzielonej maszynie MacOs, która realizuje poniższe zadania. Dodatkowo mamy tam również Android Studio, które zapewnia niezbędne narzędzia do budowania wersji Android oraz oczywiście Xcode wraz z command line tools, które pełni analogiczna funkcje dla platformy IOS.

Jenkis – Jenkins is an open source automation server written in Java – mówi Wikipedia. Kiedy posiadamy oddzielna maszynę do budowania aplikacji, Jenkins jest jednym z możliwych softu do zastosowania. Alternatyw jest wiele – odsyłam do artykułu np. tutaj – . Wszystkiego o Jenkinsie dowiesz się tutaj .

Fastlane – to zestaw skryptów napisanych w Ruby które niesamowicie ułatwiają i automatyzują proces tworzenia builda. Posiada sporo możliwości i może być używany zarówno na platformie IOS jak i Android. Po szczegóły odsyłam tutaj.

Appium – to platforma do realizowania testów UI zarówno dla IOS jak i Android (). Niewątpliwa zaleta appium jest to, że za pomocą jednego kodu testującego z niewielkimi modyfikacjami możemy przetestować dwie platformy, co jakby nie było daje oszczędność czasu. 

OK, mamy wszystkie elementy układanki – jak połączyć je tak, aby dały w rezultacie system automatycznego testowania ? 

Zaczynamy!

Pierwszym krokiem jest napisanie/stworzenie skryptu testującego. Temat ten nie jest przedmiotem tego tekstu więc zakładam, że posiadasz już taki skrypt appium umieszczony na repozytorium git. Aby móc go uruchamiać na Jenkinsie należy utworzyć zadanie, zaciągające to repozytorium na maszynę produkującą buildy a następnie wykonanie skryptu.

Należy pamiętać o odrzuceniu ścieżki do jdk do zmiennej PATH w sekcji “Inject environment variables to the build process” : 

JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home
PATH=$JAVA_HOME/bin:$PATH

A oto sama treść sekcji “Execute command” :

echo "-------------- TESTS IOS --------------"
echo "run appium"
appium --address 0.0.0.0 --port 4723 &
sleep 5

echo "run mvn test"
cd /Users/jenkins/project-dev-tests-ios/TestAutomation/
mvn test -Dsurefire.suiteXmlFiles=testng-ios.xml -Dplatform=iOS -DversionOS=12.2 -DdeviceName='iPhone X'

echo "kill appium"
kill $(ps aux | grep 'appium' | awk '{print $2}')

echo "kill simulator iPhone X"
killall "Simulator"

Startujemy appium, przechodzimy do folderu gdzie mamy skrypt testujący i uruchamiamy maven z parametrami wskazującymi na to jaki rodzaj symulatora ma być uruchomiony. Po zakończeniu testów następuje zamknięcie appium jak i symulatora. 

Wewnątrz skryptu testującego należy przekazać jakąś ścieżkę do pliku .app aplikacji – w końcu appium musi mieć aplikację do przetestowania. Zapewne wiesz, że generując archiwum z poziomu Xcode a następnie je importując otrzymujemy w efekcie plik z rozszrzeniem .ipa . Jeżeli jednak zerkniesz do jego wnętrza (ipa to tak naprawdę package – zmień rozszerzenie na zip i wypakuj – sam zobaczysz 🙂 ) to zobaczysz, że jest tam plik .app, który jest właśnie potrzebny jako wejście dla appium. Tylko jak zautomatyzować tworzenie pliku .app i wskazanie go skryptowi appium ? 

Tutaj z pomocą przychodzi Fastlane. Ustaliliśmy jeden wspólny folder dla fastlane i appium – Fastlane będzie tam wrzucał zrobione buildy, a appium będzie stamtąd pobierało plik app do testów. Fastlane posiada swój plik konfiguracyjny fastfile – dopiszemy tam lane, który zrobi to czego potrzebujemy – wykreuje plik app i wrzuci go do wskazanego folderu. Skorzystamy w tym celu z polecenia fastlane xc build. Oto fragment naszego fastfile:

desc "Debug simulator build for automated UI appium tests"
        lane :dev_sim do
        clear_derived_data
        xcbuild(
            workspace: "Project.xcworkspace",
            scheme: "PROJECT-Dev",
            configuration: "Debug",
            xcargs: "-sdk iphonesimulator SYMROOT='~/appium_test_builds/ios/project' -UseModernBuildSystem=NO"
        )
    end

Na początku czyścimy folder derived data – to przydatna funkcja – nie raz zdarza się że po jakichś zmianach projekt nie chce się skompilować i pomaga tylko clean. 

Polecenie build ma kilka parametrów – nazwa workspace, nazwa schematu, typ konfiguracji i ostatni – dla nas najważniejszy parametr – xcargs. Tutaj możemy podstawić argumenty, które trafiają bezpośrednio do xcodowego polecenie budowania builda xcodebuild. W naszym przypadku jest to wskazanie typu SDK na symulator, podanie ścieżki do miejsca gdzie składowane mają być pliki wynikowe (SYMROOT) oraz skorzystanie z legacy build system. 

argument -sdk iphonesimulator każe użyć najnowszej wersji sdk dostępnego na naszej maszynie – w chwili obecnej to ios 12.2, można jednak wskazywać dowolne sdk zainstalowane w Xcode. Aby zainstalować dodatkowe symulatory wejdź w Xcode/Preferences/Components.

Mamy już nowiutki lane w pliku fastfile – możemy z niego skorzystać przy budowaniu wersji na Jenkinsie. Należy w tym celu utworzyć zadanie Jenkinsa, i w sekcji “Execute shell” wrzucić : 

bundle exec fastlane dev_sim

W przypadku pracy z fastlane, samo fastlane zwraca uwagę w outpucie command line, że należy zadbać o obecność pewnych zmiennych środowiskowych – dodajemy je w sekcji “Inject environment variables to the build process”: 

LANG=en_US.UTF-8
LANGUAGE=en_US.UTF-8
LC_ALL=en_US.UTF-8

Mamy już zadanie Jenkinsa tworzące plik app niezbędny do testowania, mamy również zadanie uruchamiające appium i wykonujące testy. Należałoby jeszcze połączyć je jakoś, aby nie trzeba było manualnie uruchamiać dwóch zadań. Możemy to zrobić używając fajnej opcji Jenkinsa – Build Triggers.

 Definiując w naszym zadaniu testującym triggerowanie tego zadania gdy inny projekt zakończy się powodzeniem tworzymy niejako łańcuch zadań na Jenkins. Jeżeli proces tworzenia pliku app z naszej aplikacji zakończy się powodzeniem – uruchamia się dla niego test UI.

I zrobione – DZIAŁA 🙂 

Co dalej ? 

Poprawne wykonanie testów UI oznacza że obecnie testowana wersja jest z dużą dozą prawdopodobieństwa pozbawiona błędów regresyjnych. Równie dobrze można by więc dodać do naszego łańcucha zadań automatyczne tworzenie builda typu release i wrzucanie go na sklep Apple do review. To już jednak jest temat na zupełnie inną historię :).

Rate this post