en
de

Continuous Delivery für iOS Apps

4 August 2013
| |
Lesezeit: 5 Minutes

Continuous Delivery erfreut sich bei der Entwicklung von Desktop- und Webapplikationen grosser Beliebtheit.  Automatisiertes Testen, fortlaufende Integration und Verteilung der Software sind vor allem bei grösseren Projekten kaum mehr wegzudenken und haben sich zur Best Practice bei der Softwareentwicklung etabliert.

Bei der Entwicklung von iOS Apps für Smartphones oder Tablets, ist Continuous Delivery trotzdem selten anzutreffen. Häufig werden Testing, Integration und Verteilung der Software manuell durchgeführt. Dies ist vor allem darauf zurückzuführen, dass Apple kein funktionierendes Toolset zur Verfügung stellt, das ein Continuous Delivery ermöglichen würde.

Ich stelle im Folgenden deshalb eine Möglichkeit vor, wie eine App fürs iPhone oder iPad vollautomatisiert getestet, integriert und verteilt werden kann.

Automatisiertes Testen

Die Grundlage, damit eine App regelmässig automatisiert ausgeliefert werden kann, sind automatisiert ausführbare Tests. Damit eine App umfänglich getestet werden kann, werden sowohl Unit-, Integration- sowie  UI Tests benötigt.

Unit und Integration Tests

Für Unit- und Integration Tests empfiehlt es sich, ein eigenes Target im XCode anzulegen. XCode schlägt dies bei der Erstellung jedes neuen Projekts vor und übernimmt falls gewünscht des Anlegen und Konfigurieren des neuen Targets. Die Unit- und Integrationtests werden dann mit dem in XCode integrierten Testframework OCUnit umgesetzt. Fürs Mocken von Objekten verwenden wir die Library OCMock.

Mit diesem Toolset können nun Units oder abgrenzbare Module unabhängig in einem separaten Testtarget getestet werden. Die Tests können via XCode lokal und ohne Abhängigkeiten auf jedem Entwicklerrechner laufen gelassen werden.

UI Tests

Für die Umsetzung von UI Tests verwenden wir Frank. Wir verzichten dabei bewusst auf Apples UI Automation API, die das Testen von User Interfaces mittels Javascript zulässt. Obwohl UIAutomation von Apple selber stammt, ist die Anbindung und Visualisierung im XCode nicht sonderlich hilfreich. Ausserdem präsentiert sich die Organisation von Testskripts als grosse Herausforderung.

Deshalb haben wir uns noch Alternativen umgesehen und sind auf Frank gestossen. Frank basiert auf Cucumber. UI Tests mit Frank werden in der Beschreibungssprache Gherkin (given – when – then) verfasst. Ein Frank Test sieht beispielsweise wie folgt aus:

Given I launch the app
When I touch the button marked help
Then I am on the help screen

Frank liefert die gängigsten UI-Manipulationen wie zum Beispiel Drücken von Buttons oder Anwählen von Tabellenzellen mit. Damit können ohne grossen Aufwand die gängigsten Usecases in einer App durchlaufen und getestet werden. Werden weitere Manipulationen wie zum Beispiel applikationsspezifische Gesten benötigt, so können sie in Ruby hinzugefügt werden.

Um die UI Tests unabhängig von Umsystemen zu machen, haben wir ein einfaches Servlet implementiert, das wir lokal oder remote auf einem Server ansprechen können. Das Servlet antwortet auf alle Anfragen mit vordefinierten Antworten. Somit sind die UI Tests unabhängig von allfälligen Umsystemausfällen. Wichtig ist dabei, dass die Netzwerkkommunikation seitens der App identisch zur produktiven Version  abläuft. Jede Funktion, ja sogar jede Codezeile, die bei einem produktiven Backendaufruf durchlaufen wird, wird auch bei einem Aufruf auf unser Servlet getestet. Würden die Backendaufrufe intern in der App gemockt, so würden die UI Tests einen Grossteil des Netzwerklayers nicht testen, was wir unbedingt vermeiden wollten.

Um Frank Tests laufen zu lassen, muss zuerst Ruby und darauf aufbauend das Gem frank-cucumber installiert werden. Danach können Frank UI Tests via Kommandozeile gestartet werden. Während die Tests durchlaufen werden, kann man beobachten, wie im Simulator oder alternativ auch auf einem angeschlossenen Device die definierten Steps durchlaufen werden. Ein Report der Testergebnisse kann entweder direkt im Terminal oder im HTML Format im Browser angezeigt werden.

Continuous Integration

Damit der entwickelte Sourcecode nicht nur getestst, sondern auch laufend integriert werden kann, sind zwei Dinge von Nöten: Eine Software Versionsverwaltung und ein Continuous Integration (CI) Server. Wir arbeiten zur Zeit mit SVN als Versionsverwaltung, möglich wäre problemlos auch die Verwendung von GIT. Da iOS Software nur auf Apple Hardware gebaut werden kann, verwenden wir einen Mac mini als Server. Darauf installiert ist die CI Software Jenkins.

Jenkins ist so konfiguriert, dass bei jedem SVN Commit, sowie jeweils einmal in der Nacht die App gebaut wird und somit die Änderungen aller Entwickler integriert werden. Bei jeder Integration wird die App einmal im Debug und einmal im Release Modus gebaut und je ein IPA File generiert. Speziell das Bauen im Release Modus hat sich als wertvoll herausgestellt, da der Release Modus auf lokalen Entwicklermaschinen selten verwendet wird. Da dabei aber teilweise andere Libraries gelinkt werden oder abweichende Pfade gelten, werden so Fehler erkannt, die früher erst beim finalen Bauen der App für den App Store aufgetreten sind. Nachdem die App für beide Modi gebaut wurde, führt Jenkins die Unit-, und Integrationtests aus. Dafür verwenden wir das XCode Jenkins Plugin. Es erlaubt auf einfache Art und Weise, das separate XCode Test Target einzeln auszuführen. Die UI Tests werden danach von Jenkins via Skript gestartet, da für Frank leider aktuell noch kein Plugin existiert.

Somit erhalten wir nach jedem Commit und zusätzlich jede Nacht einen integrierten Build, der in zwei installationsfertigen IPA Files resultiert, sowie ein visuelles Feedback über den Erfolg aller unserer ausgeführten Tests.

Continuous Deployment

Damit der regelmässig erstellte und integrierte Build unserer App auch an alle Stakeholder verteilt werden kann, setzen wir das Tool Testflight ein. Testflight unterstützt das Betatesting von Apps. IPA Files können hochgeladen und an vorkonfigurierte Benutzer versandt werden. Die ausgewählten Benutzer erhalten von Testflight daraufhin eine Mail, aus der sie mit einem Klick die versandte App auf ihr Device installieren können. Sobald die App dann verwendet wird, rapportiert Testflight die Benutzung und zeichnet allfällige Abstürze inklusive Stacktraces auf. Die Entwickler haben via Webinterface jederzeit Zugriff auf die Verwendungsdaten und die aufgezeichneten Crashes ihrer App und können diese als Feedback für die weitere Entwicklung oder Fehlersuche verwenden.

Testflight bietet ebenfalls ein Plugin für Jenkins an. Dieses ermöglicht das automatisierte Versenden von auf dem CI Server gebauten Applikationen. Unsere Konfiguration versendet jeweils den nächtlichen Build, allerdings nur, wenn alle Tests erfolgreich durchlaufen wurden. Somit stellen wir sicher, dass sowohl Entwickler, UI Team, Tester, aber auch Projektleiter und Business jederzeit die aktuellste Version unserer App auf ihrem Gerät installieren und uns dazu Feedback geben können.

Fazit

Das vorgestellte Toolset ermöglicht uns, Änderungen am Source Code nicht nur manuell oder lokal auf dem Entwicklungsrechner, sondern auch automatisiert und integriert mit Änderungen aller anderer Entwicklern zu testen. Falls unsere Testsuiten eine gute Testabdeckung haben, bekommen wir ein schnelles Feedback, ob unsere App sich so verhält wie gewünscht. Viel mehr noch, die regelmässige Verteilung an alle Stakeholder ermöglicht einen schnellen Feedbackzyklus zum aktuellen Stand der Entwicklung.

Leider ist das Aufsetzen des vorgestellten Toolsets mit einigen Hürden verbunden. Aufwendig ist zum Beispiel das Handling des Provisioning Profiles, das für das Signieren des IPA Files benötigt wird. Auch werden teilweise Einstellungen bei Updates vom Betriebssystem auf dem Mac mini, XCode oder dem iOS SDK verändert, was zu einem nicht vernachlässigbaren Wartungsaufwand führt.

Was sich bisher als nicht mit vernünftigem Aufwand automatisieren lässt, sind Tests, die Spezialfälle von mobilem Verhalten abdecken. So testen wir beispielsweis schwache oder wechselnde Netzwerkverbindung des iPhones noch immer manuell.Das vorgestellte Toolset hat sich aber dennoch bewährt und seinen Teil dazu beigetragen, die Entwicklung von iOS Apps zu vereinfachen.

Kommentare (1)

[…] delivery or even automated testing. That was at least the case in 2013, as stated by Reto Zenger: Continuous Delivery für iOS Apps. If you have already tried to run your iOS tests with the command xcodebuild and then read the log […]

×

Updates

Schreiben Sie sich jetzt ein für unsere zwei-wöchentlichen Updates per E-Mail.

This field is required
This field is required
This field is required

Mich interessiert

Select at least one category
You were signed up successfully.