2015-12-17 24 views
25

Ich versuche, UI-Tests in meinem iOS-Projekt zu integrieren, aber eine Sache, die mich weiterhin hält, ist die Tatsache, dass es scheint, dass alle von Ihnen geschriebenen Tests von Anfang an beginnen müssen die App und arbeiten sich durch. Wenn ich beispielsweise eine Ansicht testen möchte, die sich hinter einem Anmeldebildschirm befindet, müssen meine Tests zuerst auf dem Anmeldebildschirm ausgeführt werden, geben Sie einen Benutzernamen/ein Passwort ein, klicken Sie auf Anmelden und gehen Sie zu der Ansicht, die ich testen möchte. Idealerweise sind die Tests für die Login-Ansicht und die nächste vollständig isoliert. Gibt es eine Möglichkeit, dies zu tun, oder fehlt mir die Philosophie hinter UI-Tests vollständig?iOS-Benutzeroberfläche Testen auf einer isolierten Ansicht

+0

ich das wirklich will wirklich wirklich schön arbeiten ly: app startet sauber, der Testcode entscheidet, wie der VC dargestellt wird, und der Testcode verwendet die Automatisierung, um mit der Benutzeroberfläche zu interagieren. Dies ist ein UI-Unit-Test. Alle meine Forschung zu diesem Thema ist hier https://gist.github.com/fulldecent/529849bc5dd4464bbde2 vielleicht kann jemand anderes die Fackel abholen. –

Antwort

-1

Leider ist das von Ihnen beschriebene Szenario mit UI-Tests nicht möglich.

Ein Ansatz, den ich anstellen kann, besteht darin, meine Tests in "Flüsse" von Features zu gruppieren. Nehmen wir zum Beispiel an, ich möchte Feature A, Feature B und Feature C testen. Ich muss angemeldet sein, damit alle drei funktionieren.

Für jeden Test starte ich die App nicht, melde mich an und starte dann den eigentlichen Test. Stattdessen starte ich die App und logge mich einmal ein. Dann gruppiere ich meinen Test in drei private Hilfsmethoden, testFeatureA(), testFeatureB() und testFeatureC().

Durch die Erstellung eines einzigen Ablaufs dauert die Ausführung der Testsuite viel kürzer. Der große Nachteil ist, dass Feature B, wenn Feature A fehlschlägt, niemals getestet wird. Dieser Ansatz sollte nur verwendet werden, wenn Sie sich darum kümmern, ob alle Ihrer Tests bestehen oder nicht.

Bonuspunkte für die Verwendung eines XCTest helper mit den Parametern __LINE__ und __FILE__ voreingestellt. Dann können Sie diese in Ihre XCTFail() Anrufe übergeben, um die Fehlerlinie auf testFeatureA() anzuzeigen.

+0

Downvoted wie es tatsächlich möglich ist (siehe quällische Antwort) –

19

Absolut!

Was Sie brauchen, ist eine saubere Anwendungsumgebung, in der Sie Ihre Tests ausführen können - eine leere Tafel.

Alle Anwendungen verfügen über einen Anwendungsdelegaten, der den anfänglichen Status der Anwendung einrichtet und beim Start einen Root View-Controller bereitstellt. Zu Testzwecken wollen Sie nicht, dass das passiert - Sie müssen in der Lage sein, isoliert zu testen, ohne dass all diese Dinge passieren. Idealerweise möchten Sie, dass der Bildschirm angezeigt wird und nur dieser Bildschirm geladen wird und keine anderen Statusänderungen auftreten.

Um dies zu tun, können Sie ein Objekt nur zum Testen erstellen, das implementiert UIApplicationDelegate. Sie können festlegen, dass die Anwendung im Testmodus ausgeführt wird, und den testspezifischen Anwendungsdelegaten mithilfe eines Startarguments verwenden.

Objective-C: main.m:

int main(int argc, char * argv[]) { 
NSString * const kUITestingLaunchArgument = @"org.quellish.UITestingEnabled"; 

    @autoreleasepool { 
     if ([[NSUserDefaults standardUserDefaults] valueForKey:kUITestingLaunchArgument] != nil){ 
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([TestingApplicationDelegate class])); 
     } else { 
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([ProductionApplicationDelegate class])); 
     } 
    } 
} 

Swift: main.swift:

let kUITestingLaunchArgument = "org.quellish.UITestingEnabled" 

if (NSUserDefaults.standardUserDefaults().valueForKey(kUITestingLaunchArgument) != nil){ 
    UIApplicationMain(Process.argc, Process.unsafeArgv, NSStringFromClass(UIApplication), NSStringFromClass(TestingApplicationDelegate)) 

} else { 
    UIApplicationMain(Process.argc, Process.unsafeArgv, NSStringFromClass(UIApplication), NSStringFromClass(AppDelegate)) 
} 

Sie jede @UIApplicationMain Anmerkung aus Ihrem Swift Klassen zu entfernen haben.

Für „Anwendungstests“ sollten Sie die „Test“ Aktion des Systems in Xcode, um den Start Argument zu liefern:

Xcode Scheme editor

Für UI-Tests können Sie die Einführung Argumente als Teil Satz der Test:

Objective-C:

XCUIApplication *app = [[XCUIApplication alloc] init]; 
[app setLaunchArguments:@[@"org.quellish.UITestingEnabled"] ]; 
[app launch]; 

Swift:

let app = XCUIApplication() 
app.launchArguments = [ "org.quellish.UITestingEnabled" ] 
app.launch() 

Dies ermöglicht den Tests, einen Anwendungsdelegierten speziell zum Testen zu verwenden. Das gibt Ihnen viel Kontrolle - Sie haben jetzt ein unbeschriebenes Blatt zum Testen. Der Testanwendungsdelegat kann ein bestimmtes Storyboard laden oder eine leere UIViewController einfügen. Als Teil Ihrer UI-Tests können Sie den zu prüfenden View-Controller instanziieren und ihn als Root-View-Controller keyWindow festlegen oder modal präsentieren. Sobald es hinzugefügt oder präsentiert wurde, können Ihre Tests ausgeführt werden, und wenn es vollständig ist, entfernen Sie es oder schließen Sie es.

+4

Diese Lösung scheint wirklich nett zu sein! 'NSUserDefaults.standardUserDefaults(). ValueForKey (kUITestingLaunchArgument)! = Nil' hat jedoch nicht für mich funktioniert. Ich habe es in NSProcessInfo.processInfo() .arguments.contains (kUITestingLaunchArgument) geändert, damit es funktioniert. –

+0

@FyodorVolchyok Ich würde sehr empfehlen, ein Radar zu archivieren, da Benutzereinstellungen funktionieren sollten. Launch-Argumente ersetzen andere Standardwerte, da sie sich in der Argumentdomäne befinden. – quellish

+0

@quellish Sie können ein UIStoryboard nicht einfach im Test laden (es sei denn, Sie legen eine private Variable wie in Ihrem Post http://quellish.tumblr.com/post/135415677047/ios-application-and-ui-testing-in-isolation offen). Was ich tue, ist, zusätzliche Argumente zu verwenden, damit das TestAppDelegate erkennt, dass UIStoryboard und UIViewController instanziieren. –

4

Wenn Sie nicht den Original-UI Laden kümmern, springt gerade auf das Ziel UI mit:

override func setUp() { 
    super.setUp() 
    continueAfterFailure = false 
    XCUIApplication().launch() 
    let storyboard = UIStoryboard(name: "MainStoryboard", bundle: NSBundle.mainBundle()) 
    let controller = storyboard.instantiateViewControllerWithIdentifier("LanguageSelectController") 
    UIApplication.sharedApplication().keyWindow?.rootViewController = controller 
} 

Wenn Sie die ursprüngliche UI nicht unter mögen dann auch in diesem von Ihrem Test bestehen laden:

app.launchArguments.append("skipEntryViewController") 

und dann in didFinishLaunchingWithOptions, können Sie überprüfen:

if NSProcessInfo.processInfo().arguments.contains("skipEntryViewController") { 
    // then do NOT call makeKeyAndVisible 
} 
+0

Die Frage gibt an, dass ein sauberes und isoliertes Testen benötigt wird, das ist es nicht. –

+0

Wie wird diese Anforderung nicht erfüllt? –

+0

Wenn Sie den gleichen Anwendungsdelegaten und die ursprüngliche Benutzerschnittstelle laden, kann dies zu Störungen führen. –

Verwandte Themen