web-dev-qa-db-ja.com

分離ビューでのiOS UIテスト

私は私のiOSプロジェクトにUIテストを組み込もうとしていますが、私が気を付け続けていることの1つは、作成するすべてのテストがアプリの最初から開始し、順調に進む必要があるという事実です。たとえば、ログイン画面の背後にあるビューをテストする場合、テストはまずログイン画面で実行し、ユーザー名/パスワードを入力して、[ログイン]をクリックしてから、テストするビューに移動する必要があります。ログインビューと次のビューのテストは完全に分離されるのが理想的です。これを行う方法はありますか、またはUIテストの背後にある哲学を完全に逃していますか?

31
mike

絶対に!

必要なのは、テストを実行できるクリーンなアプリケーション環境、つまり白紙の状態です。

すべてのアプリケーションには、アプリケーションの初期状態を設定し、起動時にルートビューコントローラーを提供するアプリケーションデリゲートがあります。テストの目的では、それが起こらないようにしたいのですが、それらすべてが起こらずに、単独でテストできる必要があります。理想的には、画面をアンダーテストしてその画面のみをロードし、他の状態の変化は起こさないようにする必要があります。

そのためには、UIApplicationDelegateを実装するテスト専用のオブジェクトを作成できます。 「テストモード」で実行するようにアプリケーションに指示し、起動引数を使用してテスト固有のアプリケーションデリゲートを使用できます。

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))
}

Swiftクラスから@UIApplicationMainアノテーションを削除する必要があります。

「アプリケーションテスト」の場合は、スキームの「テスト」アクションをXcodeで設定して、起動引数を指定してください。

Xcode Scheme editor

UIテストの場合、テストの一部として起動引数を設定できます。

Objective-C:

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

迅速:

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

これにより、テストはアプリケーションデリゲートをテスト専用に使用できます。これにより、多くの制御が可能になります。これで、テストのために使用する空白のスレートができました。テストアプリケーションのデリゲートは、特定のストーリーボードを読み込むか、空のUIViewControllerを配置できます。 UIテストの一部として、テスト対象のビューコントローラーをインスタンス化し、keyWindowのルートビューコントローラーとして設定するか、モーダルで表示することができます。追加または表示されると、テストを実行できます。完了したら、削除または却下します。

25
quellish

元のUIの読み込みを気にしない場合は、次のコマンドでターゲットUIにジャンプします。

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
}

下の元のUIをロードしたくない場合は、テストからこれも渡します。

app.launchArguments.append("skipEntryViewController")

didFinishLaunchingWithOptionsでは、次のことを確認できます。

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