55

Xcode 7 の新しい UI テスト機能を使用して UI テスト ケースを作成しています。アプリのある時点で、ユーザーにカメラへのアクセスとプッシュ通知の許可を求めます。"MyApp Would Like to Access the Camera"そのため、ポップアップとポップアップの 2 つの iOS ポップアップが表示されます"MyApp Would Like to Send You Notifications"。テストで両方のポップアップを閉じるようにしたいと思います。

UI の記録により、次のコードが生成されました。

[app.alerts[@"cameraAccessTitle"].collectionViews.buttons[@"OK"] tap];

ただし、[app.alerts[@"cameraAccessTitle"] exists]false に解決され、上記のコードはエラーを生成します: Assertion Failure: UI Testing Failure - Failure getting refresh snapshot Error Domain=XCTestManagerErrorDomain Code=13 "Error copying attributes -25202".

では、テスト中に大量のシステム アラートを無視する最善の方法は何でしょうか? システム ポップアップによってアプリ フローが中断され、通常の UI テスト ケースがすぐに失敗します。実際、通常のフローのテストを再開できるように、システム アラートをバイパスする方法に関する推奨事項は高く評価されています。

この質問は、答えがないこの SO 投稿に関連している可能性があります。Xcode UI テスト | 位置情報サービスのアラートを処理するには?

前もって感謝します。

4

10 に答える 10

2

特定のシステム ダイアログ (私が行ったように) の特定の説明を探している人には、何もありません :) 文字列は、テスターの追跡目的のためだけのものです。関連するアップル ドキュメント リンク: https://developer.apple.com/documentation/xctest/xctestcase/1496273-adduiinterruptionmonitor


更新:xcode 9.2

このメソッドは、トリガーされる場合とトリガーされない場合があります。私にとって最善の回避策は、システムアラートが発生することがわかっている場合です。追加します:

sleep(2)
app.tap()

システムアラートはなくなりました

于 2018-02-27T14:42:38.897 に答える
1

神!私は、XCTest が UIView アラートを処理するのに最悪の時間を費やしているのが嫌いです。私は 2 つのアラートを受け取るアプリを持っています。最初のアラートでは、アプリのアクセス許可に対して位置情報サービスを有効にするために「許可」を選択する必要があり、次にスプラッシュ ページで、ユーザーは「位置情報をオンにする」という UIButton を押す必要があり、最後にUIViewAlert で通知 SMS アラートが表示され、ユーザーは「OK」を選択する必要があります。私たちが抱えていた問題は、システム アラートと対話できないことでした。また、競合状態が発生し、動作と画面上での表示がタイムリーではありませんでした。XCTest のロジックを使用するalert.element.buttons["whateverText"].tapと、テストの時間がなくなるまで押し続けるようです。したがって、基本的には、すべてのシステム アラートが見えなくなるまで、画面上の何かを押し続けます。

これはハックですが、これが私にとってはうまくいきました。

func testGetPastTheStupidAlerts() {
    let app = XCUIApplication()
    app.launch()
    
    if app.alerts.element.collectionViews.buttons["Allow"].exists {
        app.tap()
    }

    app.buttons["TURN ON MY LOCATION"].tap()
}

文字列「許可」は完全に無視されapp.tap()、アラートが表示されるたびにロジックが呼び出され、最後に到達したかったボタン [「場所をオンにする」] にアクセスでき、テストに合格します。

〜完全に混乱しました。Apple に感謝します。

于 2016-08-04T06:55:38.987 に答える
0

@Joe Masilottiの答えは正しいです。そのおかげで、とても助かりました:)

1 つ指摘したいのは、UIInterruptionMonitorが一連のTOGETHERで提示されるすべてのシステム アラートをキャッチするため、完了ハンドラで適用するアクションがすべてのアラートに適用されることです ( 「許可しない」または「OK」 " )。アラート アクションを別の方法で処理したい場合は、完了ハンドラー内で、静的テキストをチェックするなどして現在表示されているアラートを確認する必要があります。その後、アクションはそのアラートにのみ適用されます。

以下は、一連の 3 つのアラートの 2 番目のアラートに「許可しない」アクションを適用し、残りの 2つのアラートに「OK」アクションを適用するための小さなコード スニペットです。

addUIInterruptionMonitor(withDescription: "Access to sound recording") { (alert) -> Bool in
        if alert.staticTexts["MyApp would like to use your microphone for recording your sound."].exists {
            alert.buttons["Don’t Allow"].tap()
        } else {
            alert.buttons["OK"].tap()
        }
        return true
    }
app.tap()
于 2018-04-11T14:08:59.177 に答える
0

これは古い質問ですが、これらのアラートを処理する別の方法があります。

システム アラートは、起動したアプリのアプリ コンテキストからはアクセスできませんが、アプリ コンテキストにはアクセスできます。次の簡単な例を見てください。

func testLoginHappyPath() {
    let app = XCUIApplication()
    app.textFields["Username"].typeText["Billy"]
    app.secureTextFields["Password"].typeText["hunter2"]
    app.buttons["Log In"].tap()
}

シミュレーターが既に起動されており、アクセス許可が既に付与または拒否されている真空状態では、これは機能します。しかし、まったく新しいシミュレーターを取得する CI パイプラインにそれを配置すると、通知アラートがポップアップするため、突然ユーザー名フィールドを見つけることができなくなります。

したがって、それを処理する方法には3つの選択肢があります。

暗黙的に

既定のシステム アラート割り込みハンドラーが既に存在します。したがって、理論的には、その最初のフィールドでテキストを入力しようとするだけで、割り込みイベントをチェックし、肯定的に処理する必要があります。

すべてが設計どおりに機能する場合、コードを記述する必要はありませんが、中断が記録され、ログに処理されていることがわかり、テストにはさらに数秒かかります。

割り込みモニターを介して明示的に

これに関する以前の作業を書き直すつもりはありませんが、ここでは、ポップアップする特定のアラート、または発生すると予想されるアラートを処理するために、interruptmonitor を明示的に設定します。

これは、組み込みのハンドラーが意図したとおりに動作しない場合、またはまったく機能しない場合に役立ちます。

XCUITest フレームワークを介して明示的に

xCode 9.0 以降では、複数のXCUIApplication()インスタンスを定義するだけで、アプリのコンテキストをスムーズに切り替えることができます。次に、使い慣れた方法で必要なフィールドを見つけることができます。したがって、これを明示的に行うと、次のようになります。

func testLoginHappyPath() {
    let app = XCUIApplication()
    let springboardApp = XCUIApplication(bundleidentifier: "com.apple.springboard")

    if springboardApp.alerts[""FunHappyApp" would like permission to own your soul."].exists {
        springboardApp.alerts.buttons["Allow"].tap()
    }

    app.textFields["Username"].typeText["Billy"]
    app.secureTextFields["Password"].typeText["hunter2"]
    app.buttons["Log In"].tap()
}
于 2020-08-20T23:14:15.013 に答える
-1

カメラへのアクセスと通知を実装するアプローチのように聞こえますが、あなたが言うようにスレッド化されていますが、物理的に管理されておらず、いつ、どのように表示されるかは偶然に任されています.

一方が他方によってトリガーされ、プログラムでクリックすると、もう一方も消去されると思われます(これはおそらくAppleが決して許可しないでしょう)

ユーザーの許可を求めてから、ユーザーに代わって決定を下すことを考えてみませんか? なんで?おそらくコードを機能させることができないからです。

修正方法 - これら 2 つのコンポーネントがポップアップ ダイアログをトリガーしている場所をトレースします - それらはどこで呼び出されていますか?

ユーザー向けのダイアログボタンをプログラムでクリックするというアプローチを真剣に思いとどまらせます。

于 2015-08-24T13:53:52.203 に答える