Einführung in das Testen unter iOS

Niemand möchte fehlerhafte Software versenden. Um sicherzustellen, dass Sie eine mobile Anwendung von höchster Qualität veröffentlichen, ist weitaus mehr erforderlich als ein manueller Qualitätssicherungsprozess. Neue Geräte und Betriebssysteme werden jedes Jahr der Öffentlichkeit zugänglich gemacht. Dies bedeutet, dass es eine ständig wachsende Kombination von Bildschirmgrößen und Betriebssystemversionen gibt, auf denen Sie Ihre mobile Anwendung testen müssen. Dies ist nicht nur extrem zeitaufwändig, sondern der Versuch, Ihre iOS-Anwendung durch manuelles Testen zu testen, vernachlässigt einen ganzen Teil des modernen Software-Engineering-Prozesses und automatisierte Qualitätssicherungstests.

In der heutigen Welt gibt es viele Tools, mit denen die von Ihnen geschriebene Software automatisch getestet werden kann. Einige dieser Tools werden über ein Open Source-Modell gepflegt, es gibt jedoch auch einen Kernsatz von Apple. Mit jeder neuen Version des iOS-SDK hat Apple sein Engagement für die Verbesserung der verfügbaren Tools für Entwickler zum Testen des von ihnen geschriebenen Codes unterstrichen. Für iOS-Entwickler, die sich mit automatisierten Tests noch nicht auskennen, sind Apples Tools ein guter Anfang.

1. Apple bietet hilfreiche Tools

In diesem Lernprogramm erhalten Sie Anweisungen zur Verwendung eines Tools, das von Apple für automatisierte Tests (XCTest) bereitgestellt wird. XCTest ist das Appliance-Test-Framework von Apple. Unit-Tests sind automatisierte Tests, bei denen der Code auf der untersten Ebene überprüft wird. Sie schreiben Objective-C-Code, der Methoden aus Ihrem "Produktionscode" aufruft, und überprüfen, ob der getestete Code tatsächlich das tut, was er tun soll. Sind die Variablen richtig gesetzt? Ist der Rückgabewert korrekt??

Mit dem XCTest-Framework geschriebene Tests werden möglicherweise wiederholt mit dem Code Ihrer Anwendung ausgeführt, um die Gewissheit zu gewinnen, dass Sie ein fehlerfreies Produkt erstellen, da neue Codeänderungen die vorhandene Funktionalität nicht beeinträchtigen.
Standardmäßig wird jedes neue Xcode-Projekt mit einem guten Ausgangspunkt zum Schreiben von Komponententests erstellt. Dies beinhaltet drei Dinge:

  • ein separates Ziel für Ihre Tests
  • eine Gruppe für Ihre Testklassen
  • ein Beispieltest


Sehen wir uns die Struktur eines iOS-Gerätetests an. Ein einzelner Komponententest wird als einzelne Methode in jeder Unterklasse von dargestellt XCTestCase wo die Methode zurückkehrt Leere, nimmt keine Parameter und der Methodenname beginnt mit Prüfung.

- (void) testSomething 

Glücklicherweise macht Xcode das Erstellen von Testfällen einfach. Bei neuen Xcode-Projekten wird ein erster Testfall für Sie in einer separaten Dateigruppe erstellt, deren Name mit dem Wort versehen ist Tests.

2. Erstellen Sie Ihren ersten iOS-Gerätetest

Ich habe ein Beispielprojekt erstellt, das als Referenz für die Beispiele in diesem Lernprogramm verwendet werden kann. Laden Sie das Projekt von GitHub herunter und öffnen Sie es in Xcode.

Schritt 1: Erstellen Sie die Testfallklasse

Im Beispielprojekt finden Sie die Gruppe der Tests im genannten Ordner JumblifyTests.

Um Ihren ersten Testfall zu erstellen, klicken Sie mit der rechten Maustaste auf die Dateigruppe, JumblifyTests, und wählen Sie Neue Datei. Wählen Testfallklasse von dem iOS> Quelle Abschnitt, und geben Sie der neuen Unterklasse einen Namen.

Die typische Benennungskonvention besteht darin, den Testfall so zu benennen, dass er der Name der entsprechenden getesteten Klasse mit dem Suffix ist Tests. Da werden wir das testen JumblifyViewController Klasse, nennen Sie das XCTestCase Unterklasse JumblifyViewControllerTests.

Schritt 2: Entfernen Sie den Boilerplate-Code

In der Marke neu XCTestCase Unterklasse werden Sie vier Methoden sehen. Zwei davon sind selbst Tests. Kannst du sie identifizieren? Denken Sie daran, dass die Namen der Testmethoden mit dem Wort "test" beginnen..

Wenn Sie es nicht herausgefunden haben, werden standardmäßig die Testmethoden erstellt testExample und testPerformanceExample.

Löschen Sie beide Tests, da wir unsere Tests von Grund auf schreiben werden. Die anderen beiden Methoden, Konfiguration und niederreissen, werden von der Superklasse überschrieben, XCTestCase. Das ist einzigartig Konfiguration und niederreissen werden vor bzw. nach dem Aufruf jeder Testmethode aufgerufen. Sie sind nützliche Orte, um Code zu zentralisieren, der vor oder nach dem Aufruf jeder Testmethode ausgeführt werden soll. Aufgaben wie häufige Initialisierung oder Bereinigung finden Sie hier.

Schritt 3: Verbinden Sie Ihren Test mit Ihrer getesteten Klasse

Importieren Sie die Header-Datei von JumblifyViewController Klasse und fügen Sie eine Eigenschaft des Typs hinzu JumblifyViewController zum XCTestCase Unterklasse.

@ property (nonatomic) JumblifyViewController * vcToTest;

In dem Konfiguration Methode, initialisieren Sie die Eigenschaft wie unten gezeigt.

- (void) setUp [super setUp]; self.vcToTest = [[JumblifyViewController-Zuordnung] init]; 

Schritt 4: Schreiben Sie einen Test

Wir werden jetzt einen Test schreiben, um das zu testen reverseString: Methode der JumblifyViewController Klasse.

Erstellen Sie eine Testmethode, die das instantiierte verwendet vcToTest Objekt zum Testen der reverseString: Methode. In dieser Testmethode erstellen wir eine NSString Objekt und übergeben Sie es an den View Controller reverseString: Methode. Es ist gängige Konvention, Ihrem Test einen aussagekräftigen Namen zu geben, um deutlich zu machen, was der Test testet.

- (void) testReverseString NSString * originalString = @ "himynameisandy"; NSString * reversedString = [self.vcToTest reverseString: originalString]; 

Zu diesem Zeitpunkt haben wir noch nichts Nützliches getan, weil wir das noch nicht getestet haben reverseString: Methode noch. Was wir tun müssen, ist, die Ausgabe von zu vergleichen reverseString: Methode mit dem, was wir als Ausgabe erwarten.

Das XCTAssertEqualObjects Funktion ist Teil des XCTest-Frameworks. Das XCTest-Framework bietet viele andere Methoden, um Assertions über den Anwendungsstatus zu treffen, wie z. B. Variablengleichheit oder Boolesche Ausdrucksergebnisse. In diesem Fall haben wir festgestellt, dass zwei Objekte gleich sein müssen. Wenn dies der Fall ist, ist der Test erfolgreich, und wenn nicht, schlägt der Test fehl. In der Dokumentation von Apple finden Sie eine umfassende Liste der durch das XCTest-Framework bereitgestellten Zusicherungen.

- (void) testReverseString NSString * originalString = @ "himynameisandy"; NSString * reversedString = [self.vcToTest reverseString: originalString]; NSString * expectedReversedString = @ "ydnasiemanymih"; XCTAssertEqualObjects (expectedReversedString, reversedString, @ "Die umgekehrte Zeichenfolge stimmte nicht mit der erwarteten Umkehrung überein");

Wenn Sie versuchen, den Code an dieser Stelle zu kompilieren, wird beim Aufruf eine Warnung angezeigt reverseString: aus dem Testfall. Das reverseString: Methode ist eine private Methode der JumblifyViewController Klasse. Das bedeutet, dass andere Objekte diese Methode nicht aufrufen können, da sie nicht in der Header-Datei von definiert ist JumblifyViewController Klasse.

Während das Schreiben testbaren Codes ein Mantra ist, dem viele Entwickler folgen, möchten wir unseren getesteten Code nicht unnötig ändern. Aber wie nennen wir das Private? reverseString: Methode der JumblifyViewController Klasse in unseren Tests? Wir könnten eine öffentliche Definition des hinzufügen reverseString: Methode in die Header-Datei des JumblifyViewController Klasse, aber das bricht das Einkapselungsmuster.

Schritt 5: Hinzufügen einer privaten Kategorie

Eine Lösung ist das Hinzufügen einer privaten Kategorie in der JumblifyViewController Klasse, um die zu entlarven reverseString: Methode. Wir fügen diese Kategorie dem hinzu XCTestCase Unterklasse, was bedeutet, dass es nur in dieser Klasse verfügbar ist. Durch das Hinzufügen dieser Kategorie wird der Testfall ohne Warnungen oder Fehler kompiliert.

@interface JumblifyViewController (Test) - (NSString *) reverseString: (NSString *) stringToReverse; @Ende

Schritt 6: Führen Sie den Test aus

Lassen Sie uns unsere Tests durchführen, um sicherzustellen, dass sie erfolgreich sind. Es gibt verschiedene Möglichkeiten, Komponententests für eine iOS-Anwendung auszuführen. Ich bin ein Tastaturkürzel-Junkie. Meine am häufigsten verwendete Methode zum Ausführen meiner Unit-Tests für meine Anwendung ist das Drücken von Befehl-U. Diese Tastenkombination führt alle Tests für Ihre Anwendung aus. Sie können dieselbe Aktion auch ausführen, indem Sie auswählen Prüfung von dem Produkt Speisekarte.

Wenn Ihre Testsuite wächst oder Sie eine testgetriebene Entwicklung implementieren möchten, kann die Ausführung Ihrer Testsuite zu zeitaufwändig werden. Oder es könnte Ihren Workflow behindern. Ein sehr nützlicher Befehl, eingebettet in Xcodes Menü, in den ich mich verliebt habe, ist Befehl-Option-Steuerung-U. Diese Verknüpfung löst einen Befehl aus, der den Test ausführt, in dem sich der Cursor gerade befindet. Sobald Sie Ihre Testsuite ausgearbeitet und abgeschlossen haben, sollten Sie immer die gesamte Testsuite ausführen. Das Ausführen eines einzelnen Tests ist hilfreich, wenn Sie einen neuen Test schreiben oder wenn Sie einen fehlgeschlagenen Test debuggen.

Der Befehl zum Ausführen eines Tests wird durch das Kommando ergänzt Befehl-Option-Steuerung-G, was wiederholt den letzten Testlauf. Dies kann die gesamte Testsuite sein oder nur der letzte Test, an dem Sie gerade arbeiten. Dies ist auch nützlich, wenn Sie sich von den Tests, an denen Sie gerade arbeiten, entfernt haben und noch im Debugging-Prozess sind.

Schritt 7: Überprüfen der Ergebnisse

Sie können Ihre Testergebnisse an mehreren Stellen sehen. Einer dieser Orte ist der Test Navigator zur Rechten.

Eine andere Möglichkeit besteht darin, die Dachrinne zu betrachten Quelleditor.

Wenn Sie an einer dieser beiden Stellen auf den grünen Diamanten mit dem weißen Häkchen klicken, wird der betreffende Test erneut ausgeführt. Bei einem fehlgeschlagenen Test sehen Sie einen roten Diamanten mit einem weißen Kreuz in der Mitte. Wenn Sie darauf klicken, wird der betreffende Test erneut ausgeführt.

3. Neu in Xcode 6

Xcode 6 hat zwei neue aufregende Ergänzungen zum Komponententest unter iOS und OS X eingeführt, die die asynchrone Funktionalität testen und die Leistung eines bestimmten Codeteils messen.

Asynchrones Testen

Vor Xcode 6 gab es keine gute Möglichkeit, asynchronen Code zu testen. Wenn Ihr Gerätetest eine Methode aufgerufen hat, die asynchrone Logik enthielt, konnten Sie die asynchrone Logik nicht überprüfen. Der Test würde abgeschlossen sein, bevor die asynchrone Logik in der zu testenden Methode ausgeführt wurde.

Zum Testen von asynchronem Code hat Apple eine API eingeführt, mit der Entwickler eine Erwartung definieren können, die erfüllt sein muss, damit der Test erfolgreich abgeschlossen werden kann. Der Ablauf ist wie folgt: Definieren Sie eine Erwartung, warten Sie, bis die Erwartung erfüllt ist, und erfüllen Sie die Erwartung, wenn die Ausführung des asynchronen Codes abgeschlossen ist. Schauen Sie sich das Beispiel unten zur Verdeutlichung an.

- (void) testDoSomethingThatTakesSomeTime XCTestExpectation * completionExpectation = [SelbsterwartungWithDescription: @ "Lange Methode"]; [self.vcToTest doSomethingThatTakesSomeTimesWithCompletionBlock: ^ (Ergebnis NSString *) XCTAssertEqualObjects (@ "Ergebnis", Ergebnis, @ "Ergebnis war nicht korrekt!"); [CompletionExpectation erfüllen]; ]; [self waitForExpectationsWithTimeout: 5.0 handler: nil]; 

In diesem Beispiel testen wir die doSomethingThatTakesSomeTimesWithCompletionBlock Methode. Wir möchten den Erfolg oder Misserfolg unseres Tests von dem Wert abhängen, der in dem von der getesteten Methode aufgerufenen Completion-Block zurückgegeben wird.

Dazu definieren wir zu Beginn der Testmethode eine Erwartung. Am Ende der Testmethode warten wir, bis die Erwartung erfüllt ist. Wie Sie sehen, können wir auch einen Timeout-Parameter übergeben.

Die eigentliche Zusicherung des Tests erfolgt innerhalb des Completion-Blocks der zu testenden Methode, in dem wir auch die zuvor definierten Erwartungen erfüllen. Wenn der Test ausgeführt wird, wartet der Test daher, bis die Erwartung erfüllt ist, oder er schlägt fehl, wenn das Zeitlimit abläuft und die Erwartung nicht erfüllt wird.

Leistungstest

Eine weitere Ergänzung zum Komponententest in Xcode 6 ist die Möglichkeit, die Leistung eines Codes zu messen. Auf diese Weise können Entwickler Einblick in die spezifischen Timing-Informationen des getesteten Codes erhalten.

Mit Leistungstests können Sie die Frage beantworten "Wie ist die durchschnittliche Ausführungszeit für diesen Code"? Wenn es einen Abschnitt gibt, der besonders empfindlich auf Änderungen in Bezug auf die Ausführungszeit ist, können Sie Leistungstests verwenden, um die Ausführungszeit zu messen.

Sie können auch eine Baseline-Ausführungszeit definieren. Dies bedeutet, dass der Test fehlschlägt, wenn der getestete Code erheblich von dieser Basislinie abweicht. Xcode führt den getesteten Code wiederholt aus und misst seine Ausführungszeit. Verwenden Sie zum Messen der Leistung eines Codes den measureBlock: API wie unten gezeigt.

- (void) testPerformanceReverseString NSString * originalString = @ "himynameisandy"; [self measureBlock: ^ [self.vcToTest reverseString: originalString]; ]; 

Klicken Sie auf die Informationsmeldung, die angezeigt wird.

Legen Sie die Grundausführungszeit für den Leistungstest fest oder bearbeiten Sie sie.

Fazit

In diesem Lernprogramm haben Sie gelernt, wie Sie mit Xcode Komponententests erstellen, um eine iOS-Anwendung auf programmatische und automatisierte Weise zu überprüfen. Probieren Sie es aus, entweder auf einer vorhandenen Code-Basis oder auf etwas Neuem. Ganz gleich, ob Sie sich uneingeschränkt für Unit-Tests einsetzen oder hier und da ein paar Tests hinzufügen: Sie fügen Ihrem Projekt nur einen Mehrwert hinzu, indem Sie stärker geprüfte Software schreiben, die weniger anfällig für zukünftige Änderungen ist. Unit-Tests sind nur der Anfang eines automatisierten Softwaretests. Es gibt mehrere zusätzliche Testebenen, die Sie einer iOS-Anwendung hinzufügen können.