1. 始める前に
前の Codelab では、アクティビティ間のナビゲーションについて学びました。この Codelab では、インストルメンテーション テストを使用してナビゲーションをテストするさまざまなアプローチについて学びます。
前提条件
- Android Studio でテスト ディレクトリを作成している
- Android Studio で単体テストとインストルメンテーション テストを作成している
学習内容
- インストルメンテーション テストを使用して、アクティビティまたはフラグメント間の物理的なナビゲーションをテストする方法。
必要なもの
- Android Studio がインストールされているパソコン
- Words アプリの解答コード
この Codelab のスターター コードをダウンロードする
この Codelab では、Words アプリの解答コードにインストルメンテーション テストを追加します。
この Codelab のコードを取得して Android Studio で開く手順は以下のとおりです。
コードを取得する
- 指定された URL をクリックします。プロジェクトの GitHub ページがブラウザで開きます。
- プロジェクトの GitHub ページで、[Code] ボタンをクリックすると、ダイアログが表示されます。
- ダイアログで、[Download ZIP] をクリックして、プロジェクトをパソコンに保存します。ダウンロードが完了するまで待ってください。
- パソコンに保存したファイルを見つけます([ダウンロード] フォルダなど)。
- ZIP ファイルをダブルクリックして展開します。プロジェクト ファイルが入った新しいフォルダが作成されます。
Android Studio でプロジェクトを開く
- Android Studio を起動します。
- [Welcome to Android Studio] ウィンドウで [Open an existing Android Studio project] をクリックします。
注: Android Studio がすでに開いている場合は、メニューから [File] > [New] > [Import Project] を選択します。
- [Import Project] ダイアログで、展開したプロジェクト フォルダがある場所([ダウンロード] フォルダなど)に移動します。
- そのプロジェクト フォルダをダブルクリックします。
- Android Studio でプロジェクトが開くまで待ちます。
- 実行ボタン をクリックし、アプリをビルドして実行します。正常にビルドされたことを確認します。
- [Project] ツール ウィンドウでプロジェクト ファイルを見て、アプリがどのように設定されているかを確認します。
2. スターター アプリの概要
Words アプリはリストを表示するホーム画面で構成され、リストアイテムごとにアルファベットの 1 文字が割り当てられています。文字をクリックすると、その文字で始まる単語のリストが表示される画面に移動します。
3.おすすめの方法
Kotlin では、関数の通常の命名規則として「キャメルケース」を使用することが一般的です。この命名規則では、関数名の最初の文字を小文字にし、それ以降の単語の最初の文字を大文字にします(例: myCamelCaseFunction()
)。これまでに記述したテストメソッドではすべて小文字を使用し、単語間にアンダースコアを使用していました(例: my_test_function()
)。これは、関数名を長くしてテスト対象を詳細かつ明確に示すためです。テスト対象を明確にしておけば、テストに失敗した場合でも、何が原因であったのかを関数名自体からすぐに判断できます。Kotlin では、「`test function with spaces()
`」のようにメソッド名をバッククォートで囲めば、メソッド名にスペースも使用できます。なお、バッククォートは一重引用符とは別物です。チルダ記号(~)と同じキーを使って入力します。これにより、障害が発生した場合に識別しやすい、人が読める形式の関数名を作成できます。
ただ、この方法では実装時に特別な設定が必要となります。さらにこのセクションは任意です。お読みになることはおすすめしますが、「インストルメンテーション テスト ディレクトリを作成する」セクションより前に記載されている手順を踏む必要はありません。
- 関数名にスペースを使用することは、Android API レベル 30 をターゲットとしている場合にのみ有効です。それ以外の場合は、次のようなエラーが発生します。
API を変更するには、app/build.gradle に移動し、minSdkVersion
や targetSdkVersion
を変更します。
このケースでは、要件として targetSdkVersion
が 30
に設定されています。ただし、minSdkVersion
は 19
であるため、関数名にスペースを使用できるようにするには、これを 30
に変更する必要があります。この手順は必ずしも現実的でないため、機能としては「あればよいもの」であって「なくてはならないもの」ではありません。
- API 30 をターゲットとしていても、メソッドには赤い下線が付され、「Identifier not allowed in Android Projects」というメッセージが表示されます。
テストは完了するまで引き続き実行されますが、下線を消すには、Android Studio の設定に移動し、[Editor] -> [Inspections] -> [Kotlin Android] -> [Illegal Android Identifier] -> [Tests] に進みます。
[Tests] チェックボックスをオフにして、[Apply] または [OK] をクリックします。
これで、メソッド名をバッククォートで囲んでいれば、メソッドの赤い下線は表示されなくなります。
4. テスト ディレクトリを作成する
Words アプリのインストルメンテーション テスト ディレクトリを作成します。
5. インストルメンテーション テストクラスを作成する
NavigationTests.kt
という新しいクラスを作成します。
6. ナビゲーション テストを作成する
- テストランナーを指定します。
@RunWith(AndroidJUnit4::class)
- 次に、メイン アクティビティを起動します。
@get:Rule
val activity = ActivityScenarioRule(MainActivity::class.java)
navigate_to_word()
というメソッドを作成します。
@Test
fun navigate_to_word() {
}
navigate_to_word()
メソッドでは、選択するリストアイテムを選ぶ必要があります。選ぶアイテムは任意で、複数の方法により行うことができます。アダプター内での位置に基づいてアイテムを選ぶか、含まれるテキスト(つまり文字)に基づいてアイテムを選ぶことができます。RecyclerView
を直接操作する場合は、次に示す依存関係が必要となることに留意してください。
dependencies {
...
androidTestImplementation
‘com.android.support.test.espresso:espresso-contrib:3.0.2'
}
一方、テキストでアイテムを選択する場合は、前の Codelab で使用した withText()
メソッドを使用できます。このアプローチを使用してもテキストが画面に表示されない場合、テストは失敗するという点に注意してください。これについては後ほど説明します。
- 両方の方法を試せるかどうかを確認します。目的は、UI コンポーネントが見つかったらクリックすることです。
ここでは、例として文字「C」のアイテムをクリックすることを目的とし、両方のアプローチを示します。
onView(withText("C")).perform(click())
onView(withId(R.id.recycler_view))
.perform(RecyclerViewActions
.actionOnItemAtPosition<RecyclerView.ViewHolder>(2, click()))
両方のアプローチを詳しくご確認ください。いずれかのアプローチを行ってエミュレータまたはデバイスを見てみると、どちらも機能することがわかります。RecyclerViewActions
を使用すると多くのコードが必要となりますが、余分な作業を行わずに任意のアイテムをクリックできるという利点があります。最初のアプローチを試してみます。ただし、文字「C」を「Z」に変更して、もう一度テストを行います。テストは失敗し、「androidx.test.espresso.NoMatchingViewException: No views in hierarchy found matching: with text: is "Z"」というエラーが表示されます。
これは、「Z」がリストの最後にあり、アプリを起動したとき画面外にあるため、そこまでスクロールする必要があるからです。RecyclerViewAction
のアプローチでは、この点への対処法が用意されています。位置の値として 25
を渡し、エミュレータまたはデバイスを確認してみてください。
- 先ほどの例を実行すると、次のアクティビティを正常に起動できることがわかりますが、アサーションでも確認しましょう。アプリを実行して任意のリストアイテムをクリックすると、アプリバーのタイトルが「Words That Start with __」と表示されます(空白部分はクリックした文字)。これを利用して、ナビゲーションが正しく機能していることを確認できます。正しい文字列の後にクリックした文字が表示されることを、アサーションで確認するだけで済みます。以前の Codelab でも同様のアサーションを行いました。ご自身でできるかどうか試してみてください。
onView(withText("Words That Start With C")).check(matches(isDisplayed()))
7. コンセプトのレッスンとおすすめの方法
テストでは、「偽陽性」と「偽陰性」という 2 つの重要な用語を使用します。
「偽陽性」とは、なんらかの問題があってテストに失敗するはずであるにもかかわらず、合格してしまうことです。同様に「偽陰性」とは、正常でテストに合格するはずであるにもかかわらず、失敗してしまうことです。
先ほど作成したテストでは、探している文字列をハードコードしました。コードの観点から見ると、アプリで行ったように、文字列リソースから文字列を作成する方がわかりやすくなります。これは通常のアプリコードとは動作が多少異なりますが、それでも可能です。ただし、文字列の作成は厳密にはビジネス ロジックであるため、この方法で文字列を作成すると失敗する可能性があります。テストで文字列を作成する際、アプリコードでの失敗と同じ方法で失敗すると、偽陽性となります。これは、両方のコードで同じ文字列が正しく作成されなかったために、テストでの正しくないテキストとアプリで表示される正しくないテキストが一致するからです。そのため、期待される値になるよう文字列をハードコードすることをおすすめします。
8. 解答コード
9. 完了
この Codelab では次のことを行いました。
- テスト用に詳細な関数名を作成する方法を学びました。
- アクティビティまたはフラグメントで物理的なナビゲーションをテストする方法を学びました。
- 「偽陽性」と「偽陰性」について学びました。