モバイルアプリのUIテスト: 定義、種類、実施方法

著者: IT Sectr 公開日: 2026-04-07 読了時間: 8 分

UIテストは、モバイルアプリケーションのユーザーインターフェース要素の表示とインタラクションの正確さを検証します—ボタン、テキストフィールド、リスト、ナビゲーションコンポーネントなど。ビジネスロジックを検証する単体テストとは異なり、UIテストはユーザーのアクション—タップ、スワイプ、テキスト入力—をシミュレートし、インターフェースの反応を検証します。Android Developers, 2024の調査によると、UIテストは重要なユーザーシナリオの70%をカバーし、論理的なチェックでは検出できないレイアウトのデフェクトを見つけることができます。

まとめ

  • UIテスト — ユーザーのアクションのシミュレーションによってアプリケーションのユーザーインターフェースを検証するプロセス: タップ、テキスト入力、スワイプ。
  • Espresso — Googleが提供するAndroidアプリのUIテスト用フレームワーク。UIスレッドとのシンクロナイゼーションおよびアニメーションの自動待機を提供します。
  • XCUITest — Appleが提供するiOSアプリのUIテスト用ネイティブフレームワーク。Xcodeに統合され、Accessibilityラベルを介して動作します。
  • Appium — クロスプラットフォームツール。WebDriverプロトコルを使用してAndroidとiOSの両方で一つの言語でUIテストを書くことができます。
  • スナップショットテスト は、画面の視覚的な外観を検証することでUIテストを補完します—リファレンス状態のスクリーンショットと現在のレンダリングを比較します。

UIテストとは?

UIテストは、テストコードがアプリケーションのグラフィカルインターフェースと実際のユーザーと同じようにインタラクションする自動化検証の一種です。テストは画面上の要素—ボタン、テキストフィールド、リスト—を見つけ、それに対してアクションを実行し、予期されるインターフェースの反応を検証します。例えば、間違ったパスワードを入力した後、UIテストは正しいテキストのエラーメッセージが画面上に表示されるかを検証します。

UIテストと他の自動化の最大の違いは、アプリケーションの内部APIではなく、OSのアクセシビリティレイヤーを通じて動作することです。これにより、UIテストはユーザーやスクリーンリーダーと完全に同じようにインターフェースを視えます。これにより、UIテストは機能だけでなく、要素のアクセシビリティ(WCAG要件への適合)も検証できます。

JetBrains Developer Ecosystem 2023の調査によると、58%のモバイルチームがCI/CDパイプラインでUIテストを使用しています。コマーシャルプロジェクトにおけるUIテストの平均カバレッジは30–40%です。UIテストを導入しているプロジェクトは、インターフェースのクラッシュに関するアプリストアでの悪評価が25%減少しています。

UIテストと単体テストの違い

UIテストと単体テストの最大の違いは抽象度です。単体テストは、AndroidやiOSのフレームワークから離された個々のクラスや関数を扱います。これらはエミュレーターを起動せずにJVM上で実行され、ミリ秒で終了します。UIテストは実機またはエミュレーターで実行され、システムサービスとインタラクションし、シナリオごとに数秒から数分を要します。

テストの対象となる目的も異なります。UIテストはエンドツーエンドのユーザーシナリオ—登録、注文、検索—を検証します。単体テストはビジネスロジック(計算、バリデーション、データ変換)をカバーします。UIテストは税金計算の正確さを検証せず、総額が画面に表示されるかどうかを検証します。計算そのものは単体テストで検証されます。

Google Testing Blog (2020)によると、プロジェクトにおけるテストの最適割合は、テストピラミッドのルールに従い、70%が単体テスト、20%が統合テスト、10%がUIテストです。この割合をUIテスト側に破ると、実行時間が増加し、UIテストが画面レイアウトの変更に敏感なため、テストスイートが脆弱になります。

UIテストのフレームワーク

Androidでは、主導的なフレームワークはEspressoです—Googleが提供するライブラリで、AndroidX Testに組み込まれています。Espressoは自動的にUIスレッドとシンクロナイズし、次のアサーションを実行する前にアニメーションとバックグラウンドタスクの完了を待ちます。Jetpack Composeでは、伝統的なビュー識別子の代わりにセマンティックノードを使用するCompose UI Test拡張が使用されます。

iOSでは、主なツールはXCUITestで、Xcodeの一部です。テストはSwiftで書かれ、要素を見つけるためにAccessibility識別子を使用します。XCUITestはレコード機能によるテスト記録と、xcodebuildを介したCIシステムとの統合をサポートしています。クロスプラットフォームプロジェクトでは、WebDriverプロトコルに基づき、最小限のコード変更でAndroidとiOSの両方で同じテストを実行できるAppiumが使用されます。

EspressoとCompose UI Test

Espressoは、onViewとリソースID識別子を介して伝統的なビューシステムで動作します。Compose UI Testはセマンティックレイヤーを使用し、テストがビュー階層に依存することを減らします。例えば、Espressoでボタンを見つける場合: onView(withId(R.id.submit))、Composeでは: onNodeWithTag(“submit”)です。Composeテストは自動的に再構成を処理し、明示的なアイドル状態の待機が不要です。

iOS用XCUITest

XCUITestは入口点としてXCUIApplicationを使用します。各インターフェース要素は、Accessibilityプロパティ—プログラムアクセス用のaccessibilityIdentifierとVoiceOver用のaccessibilityLabel—を介して検索されます。このフレームワークは、Xcodeのレコード機能によるテスト記録をサポートしています—ディベロッパーがシミュレーターでアクションを実行すると、Xcodeがテストコードを生成します。完了したテストはxcodebuild testを介して実行されます。

クロスプラットフォーム解決策

AppiumはWebDriverプロトコルに基づき、Java、Python、JavaScriptなど様々な言語をサポートしています。要素検索策略は、id、xpath、class name、accessibility idを含みます。AppiumはサーバーのインストールとDesired Capabilities(platformName、deviceName、appPackage)の設定が必要です。代替案としては、YAMLシナリオを使用し、テストコードのコンパイルが不要なMaestroがあります。

  • Espresso — onView(withId(R.id.button)).perform(click()).check(matches(isDisplayed()))
  • XCUITest — app.buttons[“loginButton”].tap(); XCTAssertTrue(app.staticTexts[“welcome”].exists)
  • Appium — driver.findElement(By.id(“com.example:id/button”)).click()
  • Detox — React Native用のWixによるフレームワーク。JSスレッドとシンクロナイズします
  • Maestro — YAMLシナリオを使用した現代的なツール。コードを書く必要がありません

UIテストのコード例

3つの異なるフレームワークで同じシナリオ—アプリにログイン—のUIテストを見てみましょう: Android用Espresso、iOS用XCUITest、クロスプラットフォームアプローチ用Appium。シナリオ: ログインとパスワードを入力し、ログインボタンを押し、ようこそメッセージが表示されることを確認します。

Android: Espresso

Espressoテストは、onViewを使って識別子で要素を見つけ、performでアクションを実行します。isDisplayedマッチャーとのcheckメソッドは、要素が画面上に表示されていることを確認します。

kotlin
@RunWith(AndroidJUnit4::class)
class LoginUiTest {

    @Rule
    @JvmField
    val composeTestRule = createComposeRule()

    @Test
    fun login_withValidCredentials_showsWelcome() {
        composeTestRule
            .onNodeWithTag("emailField")
            .performTextInput("user@example.com")
        composeTestRule
            .onNodeWithTag("passwordField")
            .performTextInput("secret123")
        composeTestRule
            .onNodeWithTag("loginButton")
            .performClick()
        composeTestRule
            .onNodeWithText("ようこそ、ユーザーさん!")
            .assertIsDisplayed()
    }
}

iOS: XCUITest

XCUITestは、Accessibility識別子を介してインターフェース要素にアクセスするためにXCUIApplicationを使用します。tap()とexistsメソッドは、インタラクションと検証を提供します。

swift
class LoginUITests: XCTestCase {
    let app = XCUIApplication()

    override func setUp() {
        continueAfterFailure = false
        app.launch()
    }

    func testLogin_withValidCredentials_showsWelcome() {
        app.textFields["emailField"].tap()
        app.textFields["emailField"].typeText("user@example.com")
        app.secureTextFields["passwordField"].tap()
        app.secureTextFields["passwordField"].typeText("secret123")
        app.buttons["loginButton"].tap()
        XCTAssertTrue(app.staticTexts["Welcome, User!"].exists)
    }
}

UIテストの最良実践

第一の原則は—要素を見つけるためにテキストラベルではなくAccessibility識別子を使用することです。ボタンのテキストはローカライゼーションによって変わる可能性がありますが、識別子は一定です。AndroidではこれはcontentDescriptionプロパティで、iOSではaccessibilityIdentifierです。このアプローチにより、テストがインターフェース言語から独立し、コピーライティングが変わっても保守コストが削減されます。

sleep()や固定延結を避ける—フレームワークの組み込み待機メカニズムを使用します。Espressoは自動的にアニメーションとバックグラウンドタスクの完了を待ちます。XCUITestはタイムアウト付きのXCTAssertTrueを提供します。明示的な中断は、特にCI環境の遅いデバイスで、テストを遅くし不安定にします。

重要度によってテストをグループ化:スモークテスト(3–5の主なシナリオ)はコミットごとに実行され、全UIテストスイートはリリース前に実行されます。Google Testing Blog (2022)によると、CIで30分以上かかるUIテストは実行頻度が40%減少し、リグレッション早期発見ツールとしての効果が低下します。

UIテストの制約と対処法

UIテストにはいくつかの制約があります。レイアウト変更に対する敏感性: 識別子、階層、要素タイプを変更すると、機能が変わらなくてもテストが失敗します。解決策は、要素セレクターを独立したクラスにまとめるPage Objectパターンを使用することです。レイアウトが変わった場合、数十のテストではなく、一つのPage Objectファイルだけを修正します。

実行時間: 実機またはエミュレーターでの実行は、単体テストより10–50倍の時間がかかります。解決策は、Firebase Test LabやAWS Device Farmを介して複数デバイスでUIテストを並列実行することです。不安定さ(flakiness)は、アニメーション、ネットワーク延結、エミュレーターの状態によって引き起こされるCI実行の問題です。不安定さに対処するために、失敗テストの自動再実行や各テストシナリオの安定性分析が使用されます。

よくある質問

一つの画面に必要なUIテストの数は?

平均的な画面では3–5つのUIテストで十分です: ハッピーパス、エラー検証、空の状態、向き変更、Accessibilityチェック。複数の状態をもつ複雑な画面—注文フォーム、設定—では、主なシナリオを完全にカバーするために10–15のテストが必要になる場合があります。

AndroidとiOSで一つのフレームワークを使えますか?

はい、AppiumとMaestroは両プラットフォームで同じシナリオを実行できます。ただし、ネイティブフレームワーク(EspressoとXCUITest)は、より良い安定性、スピード、およびWebDriverプロキシを通じては利用できないプラットフォーム固有機能へのアクセスを提供します。

Jetpack ComposeのUIをテストするには?

Composeでは、セマンティックマッチャーを持つCompose UI Testライブラリが使用されます: onNodeWithText、onNodeWithTag、onNodeWithContentDescription。Composeのセマンティックレイヤーはビュー階層を抽象化するため、伝統的なビューシステム用のEspressoに比べてテストが脆弱になりにくくなります。

物理デバイスでUIをテストすべきですか?

基本的なUIテストはCIのエミュレーターで実行されます—速くて安いです。リリース前の最終検証は、実機の特性(異なる解像度、OSバージョン、パフォーマンス)を考慮するために、Firebase Test Labを介して物理デバイスで実行することをお勧めします。

UIテストの実行時間を縮短する方法は?

複数デバイスでの並列実行を使用し、デベロッパーオプションでエミュレーターのアニメーションを無効にし、モジュール化されたテストアーキテクチャを構築し、スモークスイートをコミットごとに実行し、全リグレッション実行はスケジュールに従ってまたはリリース前に実行します。

まとめ

  • UIテストは、ユーザーのアクション—タップ、テキスト入力、スワイプ—をシミュレートしてインターフェースを検証します。
  • EspressoとCompose UI TestはAndroidの主なフレームワークです。XCUITestはiOS用、Appiumはクロスプラットフォームプロジェクト用です。
  • テストピラミッドは70/20/10の割合を推奨しています: 単体テスト、統合テスト、UIテストの順です。
  • Accessibility識別子により、UIテストがローカライゼーションやレイアウト変更に対して耐性を持ちます。
  • Page Objectパターンは要素セレクターを集中し、インターフェース変更時の維持コストを削減します。
  • スモークテスト(3–5シナリオ)はコミットごとに実行され、全テストスイートはリリース前に実行されます。
  • エミュレーターでの並列実行とアニメーションの無効化により、CIにおけるUIテストの実行時間が縮短されます。

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください