Blog

iOS + XCode 4 + GHUnit = Mobile TDD+Kontinuierliche Tests Teil 2 von n

Robert van Loghem

Robert van Loghem

Aktualisiert Oktober 22, 2025
7 Minuten

Letztes Mal habe ich erklärt, warum ich TDD für mobile Geräte für unerlässlich halte und warum ich es tue. Aber jetzt ist es an der Zeit, technisch zu werden und Ihnen zu erklären, wie Sie GHUnit in XCode 4 einrichten und Unit-Tests ausführen, nicht nur im iPhone- und iPad-Simulator, sondern auch auf Ihrem eigenen physischen Gerät! in Text und Bildern, aber auch in Videoform auf YouTube. Wenn Sie wissen möchten, warum ich mich für GHUnit und nicht für OCUnit entschieden habe, scrollen Sie einfach bis zum Ende des Beitrags herunter.

Aber warten Sie.... Bevor ich beginne, möchte ich eine Sache klarstellen: den Unterschied zwischen Code-Unit-Tests und UI-Tests. Leider kann es schwierig sein, die UI-Entwicklung in TDD-Manier durchzuführen. Vor allem, wenn Sie UI-Komponenten testen wollen. z.B. Wenn ich ein TouchEvent sende, wird die Ansicht reagieren und meine Methode in meinem Controller auslösen.Mein Rat: Machen Sie UI-Tests nicht mit einem Unit-Testing-Framework (OCUnit, JUnit, GHUnit), sondern zum Beispiel mit der iOS-Automatisierungs-API, die speziell für das Testen dieser UI-Komponenten entwickelt wurde. Ich werde in einem späteren Beitrag darauf zurückkommen, wie Sie UI-Tests unter Android durchführen können.Was testen Sie mit Unit-Testing-Frameworks? Nun, Sie testen nur den Code, sonst nichts. Modell- und Controller-Code, nicht die Ansicht! Möglicherweise benötigen Sie die Hilfe eines Mocking-Frameworks, um es testbar zu machen, weil die View fehlt und verdrahtet werden muss, damit der Controller und das Model richtig funktionieren, oder weil sie andere Controller usw. benötigt. Beginnen wir mit dem Aufbau! Lassen Sie uns nun unser eigenes iPhone XCode 4 Projekt einrichten! Fügen Sie GHunit hinzu, erstellen Sie einen Test und führen Sie ihn im Simulator oder auf Ihrem eigenen iOS-Gerät, iPhone, iPod Touch oder iPad aus. 1. Laden Sie zunächst die Version GHUnitIOS (derzeit 0.4.28) herunter. 2. Entpacken Sie die heruntergeladene Zip-Datei irgendwo in Ihrem Home-Verzeichnis. Sie sollten das Verzeichnis GHUnitIOS.framework erhalten

HINWEIS: Ich habe sie zunächst in /Developer/Library/Frameworks abgelegt, aber XCode 4 mochte sie nicht und konnte beim Kompilieren die Header-Dateien nicht finden. Daher habe ich sie irgendwo in meinem Home-Verzeichnis abgelegt (z.B. /Users/rvanloghem/Development/Frameworks/GHUnitIOS.framework)

So, jetzt können Sie Ihr GHUnit-kompatibles XCode 4-Projekt einrichten. 3. Als Beispiel wähle ich eine normale, navigationsbasierte Anwendung, aber vielleicht haben Sie ja ein bestehendes Projekt.

  • HINWEIS: Aktivieren Sie das Kontrollkästchen Unit-Tests einbeziehen nicht, da wir unser eigenes Unit-Testing-Framework bereitstellen und uns nicht auf OCUnit verlassen wollen, das standardmäßig in XCode enthalten ist. wählen Sie Neue Projektvorlage

    4. Fügen Sie in Ihren XCode-Projekteinstellungen (blaues Wurzelsymbol im Baumbrowser) ein Ziel hinzu, das Sie Tests nennen können. In der Regel basiert das Projekt auf einer einfachen ansichtsbasierten Anwendung (ein Ziel mit dem Namen Tests wird hinzugefügt + ein Ordner mit dem Namen Tests, der alle Test-Zieldateien enthält). 5. Gehen Sie nun zurück zum Ziel Tests (klicken Sie auf das Ziel Tests) und fügen Sie das GHUnitIOS.framework hinzu, das Sie in Schritt 1 und 2 heruntergeladen und entpackt haben (klicken Sie auf die Registerkarte Build Phases, öffnen Sie Link Binary with Libraries, klicken Sie auf die Schaltfläche +, klicken Sie auf Add Other und wählen Sie das Verzeichnis GHUnitIOS.framework in Ihrem Dateisystem aus). 6. Optional, aber gut, verschieben Sie das GHUnitIOS.framework in Ihrem Baum in den Ordner Frameworks, um Ordnung zu schaffen

    1. Setzen Sie -ObjC und -all_load in den anderen Linker-Flags auf dem Test-Ziel (Wählen Sie das Test-Ziel, wählen Sie die Build-Einstellungen, suchen Sie nach anderen Linker-Flags und fügen Sie die 2 Flags hinzu).
    2. Jetzt können Sie einige nicht benötigte Dateien löschen, nämlich alle Dateien im Ordner Tests. (Achtung, nicht! auch den Ordner Supporting Files, nur die Dateien!)
    3. Löschen Sie die Datei main.m im Ordner Supporting Files
    4. Löschen Sie in der Datei Tests-Info.plist (wiederum im Ordner Supporting Files) den Wert Main nib file base name Time, um den GHUnit Test Runner zu erstellen, der nach unseren Unit Test Cases sucht und sie ausführt.
    5. Erstellen Sie im Ordner Tests eine Objective-C-Klasse mit dem Namen GHUnitIOSTestMain und stellen Sie sicher, dass sie nur! zum Ziel Tests hinzugefügt wird.
    6. Sie können die Datei GHUnitIOSTestMain.h löschen
    7. Kopieren Sie den Quellcode aus (https://github.com/gabriel/gh-unit/blob/master/Project-IPhone/GHUnitIOSTestMain.m) und fügen Sie ihn in Ihre Datei GHUnitIOSTestMain.m ein. Und nun ist es an der Zeit, unseren eigenen Testfall zu erstellen, der fehlschlagen wird ;)
    8. Erstellen Sie erneut eine Objective-C-Klasse im Ordner Tests und nennen Sie sie ExampleTest, da es sich um ein Beispiel handelt. Stellen Sie außerdem sicher, dass sie nur zum Ziel Tests hinzugefügt wird!
    9. Sie können die Datei ExampleTest.h löschen
    10. Kopieren Sie den folgenden Code, der zu 99% aus dem Beispielcode von GHUnit kopiert/eingefügt wurde
      [sourcecode language="c"]// Für iOS
      #import <GHUnitIOS/GHUnit.h>
      // Für Mac OS X
      //#import <GHUnit/GHUnit.h>
      @interface ExampleTest : GHTestCase { }
      @end
      @implementation ExampleTest
  • (BOOL)shouldRunOnMainThread { // Standardmäßig NO, aber wenn Sie einen UI-Test oder einen Test haben, der auf dem Haupt-Thread laufen muss, geben Sie YES zurück return NO; }
  • (void)setUpClass { // Wird zu Beginn aller Tests in der Klasse ausgeführt }
  • (void)tearDownClass { // Wird am Ende aller Tests in der Klasse ausgeführt }
  • (void)setUp { // Wird vor jeder Testmethode ausgeführt }
  • (void)tearDown { // Wird nach jeder Testmethode ausgeführt }
  • (void)testFoo { NSString a = @"foo"; GHTestLog (@"Ich kann auf der GHUnit-Testkonsole protokollieren: %@", a); // Assert a ist nicht NULL, ohne benutzerdefinierte Fehlerbeschreibung GHAssertNotNULL (a, nil); // Assert equalObjects, benutzerdefinierte Fehlerbeschreibung hinzufügen NSString b = @"bar"; GHAssertEqualObjects(a, b, @"Eine benutzerdefinierte Fehlermeldung. a sollte gleich sein mit: %@.", b); }
  • (void)testBar { GHAssertTrue(TRUE, @"Ja, es hat funktioniert"); } @end [/sourcecode] Gut, bereit zum Laufen!
    1. Starten Sie Ihr Test-Ziel (iTunes-ähnlicher Pfeil auf der Wiedergabetaste) und führen Sie es gegen das Simulator-Schema aus und Ihre Unit-Test-App sollte starten
    2. Klicken Sie nun in der App im Simulator auf die blaue Schaltfläche Ausführen und Ihre Tests werden ausgeführt. (und testFoo wird fehlschlagen!, Sie können darauf klicken, um zu sehen, warum er fehlgeschlagen ist) Und jetzt ist es an der Zeit, es zu reparieren...
    3. Ändern Sie die NSString b = @"bar"; in der Methode testFoo in NSString b = @"foo";
    4. Starten Sie die Test-App erneut und führen Sie den Test erneut aus. Sie sollten grün oder in diesem Fall schwarz sein, was bedeutet, dass Ihre Tests in Ordnung sind. Zeigt die Leistungsfähigkeit von GHUnit
    5. Führen Sie die App mit Ihrem eigenen iOS-Geräteschema aus. (Wählen Sie iOS-Geräteschema und klicken Sie auf die Schaltfläche iTunes like run) Warum ich GHUnit OCUnit vorziehe IMHO zeigt dies die wahre Stärke des GHUnit-Testframeworks. Es läuft nicht nur im Simulator, sondern auch auf Ihrem eigenen iPhone, iPad usw. OCUnit hingegen kann nur als Teil Ihres Builds auf Ihrem eigenen Rechner ausgeführt werden, nicht auf Ihrem Telefon und nicht im Simulator. Das ist für mich ein entscheidender Punkt. Je näher Sie Ihre Unit-Tests an eine reale Umgebung heranführen können, desto besser werden sie sein. Und warum? Denn Sie nutzen den echten Prozessor des Geräts (nicht den intel x86), die echte Speicherverwaltung (oder deren Fehlen), die echten APIs usw. Wenn meine Unit-Tests auf meinem Telefon laufen, bin ich zu 99,999% sicher, dass der getestete Code auch tatsächlich auf meinem Telefon läuft. Natürlich hat GHUnit einen Nachteil: OCUnit (in XCode enthalten) kann automatisch ausgeführt werden, bevor Sie Ihre eigene Anwendung kompilieren. Aber um dieses Problem zu lösen oder zumindest zu verbessern, können wir die kontinuierliche Integration, auch bekannt als Build-Server, nutzen, um die automatische Ausführung von Unit-Tests für uns zu erledigen. Es gibt einen sehr schönen Blog-Beitrag, der verschiedene iOS Unit-Testing-Frameworks vergleicht.Was kommt als nächstes? Nun, das Thema meines nächsten Blogs und Videos in dieser Serie ist die Anbindung eines XCode-Projekts + GHUnit an Jenkins (oder Hudson für die Oracle-affinen Leute da draußen).

Verfasst von

Robert van Loghem

I'm always interested in the latest and greatest when it comes to; communication, infrastructure, user experience and coming up with some crazy creative solution which might seem as a weird combination ;) I use and spread the word about multimedia (podcasts, vodcasts, movies, comics) to effectively communicate concepts, ideas, documentation, past experiences and so on. Furthermore i am heavy into infrastructure but then the middleware part, like HTTP servers, Application Servers, Messaging, Virtualization, etc... I get really enthousiastic if the infrastructure is clustered, highly available and is critical to doing business! I also like to do development and thus "i eat my own dogfood".

Contact

Let’s discuss how we can support your journey.