PLAY DEVELOPERS BLOG

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

UI テストツールの XCUITest と Maestro を実際の iOS アプリで比較してみた

こんにちは、iOSアプリの開発を担当しているOTTサービス技術部開発第3Gの鈴木です。

皆様、UIテストは実施しておりますでしょうか。

UIテストを実施する場面としては、リグレッションテストが多いかと思います。 そんなUIテストが自動化されているかというと、まだまだ人力で頑張っているような状況が多いかと思います。 自動化できるテストはどんどん自動化していきたいですね。

ということで、今回はiOSアプリ開発におけるUIテスト自動化ツールとして候補に上がりがちな、「XCUITest」と、「Maestro」の二つを比較します。

本記事が皆様のUIテストの導入、及びその自動化の手助けになれば幸いです。

XCUITest とは?

XCUITestとは、Appleが提供するUIテストフレームワークの一つで、iOSおよびmacOSアプリケーションのUIを自動でテストするためのツールです。 テストスクリプトはSwiftで記述します。 Xcodeと統合されており、Xcode内でテストを作成、実行、デバッグできます。

Maestro とは?

Maestroは、モバイルアプリケーションのUIテストを簡単かつ効率的に行うためのオープンソースのフレームワークです。 テストスクリプトはYAML形式で記述します。 iOSとAndroidの両方のプラットフォームをサポートしているので、同一のUIであれば、ほぼ同じ記述でテストできるところは嬉しいです。 オープンソースとして無料で利用できるところも嬉しいですね。

github.com

比較してみる

今回はサンプルアプリとして、GitHub APIを利用したRepository検索アプリを用意しました。 こちらを使用し、XCUITestとMaestroを比較していきます。

テスト内容

本テストで行うUI操作は以下になります。

  1. アプリを起動する
  2. 画面上部の検索バーを押下する
  3. 「Swift」と入力する
  4. 検索ボタンを押下する
  5. 「Swift」のRepositoryを選択する(詳細画面に遷移する)
  6. 「Back」ボタンを押下する(検索画面に戻る)
  7. 「Cancel」ボタンを押下する(検索文字・検索結果を全て削除し、「リポジトリが見つかりませんでした」の表示となる)

また、本テストでの確認項目内容は以下になります。

  1. 検索後、検索結果が画面に表示されていることを確認する
  2. 「Swift」のRepositoryを選択後、詳細画面に遷移したことを確認する
  3. 詳細画面で「Swift」のRepositoryの情報を表示していることを確認する
  4. 「Back」ボタンを押下後、検索画面に遷移したことを確認する
  5. 「Cancel」ボタンを押下後、検索結果が画面に表示されていないことを確認する

XCUITestの場合

XCUITestの場合は以下のような記述になります。

final class UITestSampleUITests: XCTestCase {
    private var app: XCUIApplication!

    override func setUpWithError() throws {
        try super.setUpWithError()
        continueAfterFailure = false
        app = XCUIApplication()

        // ACTION: ① アプリを起動
        app.launch()
    }

    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }
    
    func test_searchSwiftRepository() throws {
        let navBar = app.navigationBars["_TtGC7SwiftUI19UIHosting"]
        let searchBar = navBar.searchFields["search"]
        
        // ACTION: ② 検索バー押下
        searchBar.tap()
        
        // ACTION: ③ 「Swift」と入力する
        searchBar.typeText("Swift")
        
        // ACTION: ④ 検索ボタンを押下
        app.buttons["search"].tap()
        
        // CHECK: ① 検索結果が画面に表示されていることを確認する
        XCTAssert(app.buttons["RepositoryCell"].firstMatch.waitForExistence(timeout: 5))
        
        // ACTION: ⑤ 「Swift」のRepositoryを選択する
        app.collectionViews.staticTexts["swiftlang"].tap()
        
        // CHECK: ② 詳細画面に遷移したことを確認する
        XCTAssert(app.otherElements["RepositoryDetailView"].exists)

        // CHECK: ③ 詳細画面で「Swift」のRepositoryの情報を表示していることを確認する
        XCTAssert(app.staticTexts["The Swift Programming Language"].firstMatch.exists)
        
        // ACTION: ⑥「Back」ボタンを押下する
        navBar.buttons["Back"].tap()
        
        // CHECK: ④ 検索画面に遷移したことを確認する
        XCTAssert(app.otherElements["RepositoriesView"].exists)

        // ACTION: ⑦「Cancel」ボタンを押下する
        navBar.buttons["Cancel"].tap()
        
        // CHECK: ⑤ 検索結果が画面に表示されていないことを確認する
        XCTAssertFalse(app.buttons["RepositoryCell"].exists)
    }
}

Maestroの場合

Maestroの場合は以下のような記述になります。

appId: jp.suzuki.play.githubRepositorySearch
---
# ACTION: ① アプリを起動
- launchApp

# ACTION: ② 検索バー押下
- tapOn: "search"

# ACTION: ③ 「Swift」と入力する
- inputText: Swift

# ACTION: ④ 検索ボタンを押下
- tapOn:
    id: "Search"

# CHECK: ① 検索結果が画面に表示されていることを確認する
- assertVisible:
    id: "RepositoryCell"

# ACTION: ⑤ 「Swift」のRepositoryを選択する
- tapOn: "swiftlang"

# CHECK: ② 詳細画面に遷移したことを確認する
- assertVisible:
    id: "RepositoryDetailView"

# CHECK: ③ 詳細画面で「Swift」のRepositoryの情報を表示していることを確認する
- assertVisible: "The Swift Programming Language"

# ACTION: ⑥「Back」ボタンを押下する
- tapOn: "Back"

# CHECK: ④ 検索画面に遷移したことを確認する
- assertVisible:
    id: "RepositoriesView"

# ACTION: ⑦「Cancel」ボタンを押下する
- tapOn: "Cancel"

# CHECK: ⑤ 検索結果が画面に表示されていないことを確認する
- assertNotVisible:
    id: "RepositoryCell"

違いについて

各ツール間の違いについては、以下の三点を感じました。

  • Wait処理の記述有無
  • 実行環境
  • 複雑なUIへの対応

まず、Wait処理の記述有無についてです。 XCUITestでは、待機が必要な場合はwaitForExistence(timeout: 5)のように待機処理を記述する必要がありますが、Maestroでは記述不要なので、テストスクリプトが簡潔になります。

次に実行環境についてです。 Maestroの実行環境はSimulatorのみに限られます。 一方、XCUITestはSimulator・実機の両方で実行可能なため、実機で確認したいUIをテスト可能なことは、XCUITestの強みだと思います。

最後に複雑なUIへの対応についてです。 今回のテストではそこまで感じませんでしたが、業務でMaestroを利用している中で、 ネストが深いような複雑な作りの画面だと、MaestroにてUIパーツを判別できずテストが難しくなるようなことがありました。 複雑な画面のUITestを行う場合は、XCUITestで行うことをオススメします。

Wait処理の記述有無 実行環境 複雑なUIへの対応
XCUITest 必要 Simulator or 実機 対応可能
Maestro 不要 SImulator UIパーツの識別が困難な場合あり

まとめ

今回、「XCUITest」と「Maestro」を比較してみて、それぞれの魅力や便利さを実感することができました。 是非、これらのツールを活用してUIテストの自動化の推進を図ってみてはいかがでしょうか。