どうも。どっことです。今回は、テストコードの実装について解説したいと思います。
テストコード
テストコードは実機やエミュレータに開発段階のアプリをインストールせずとも、プログラムとしてテストを実行できるようにするものです。テストコードを実装せずとも、世の中に公開するアプリを開発することができるので、より難しい機能の実装や複雑なドメインロジックをプログラムに落とし込むなどのスキルを優先して獲得するというロードマップも考えとしてはあると思います。
ただ、昨今のCI/CDの重要性の高まりを鑑みると、テストコードを実装できることもエンジニアとして必要なスキルとして需要が上がってきているように見受けられます。そしてそんな需要が高まっている一方で、テストコードを実装できるエンジニアはまだまだ多くありません。ぜひテストコードを実装できるようになり、より広い知見をもつエンジニアへと一歩を進めましょう。
説明に入る前に(テストコードの種類)
Androidの開発においては、大きく2種類のテストコードがあります。
ユニットテスト
開発PC上で実行されるテストコードです。Androidの機能に依存しないビジネスロジックやアプリケーションロジックに対するテストコードを実装する際のものとなります。開発PC上で実行されるため、後述のインストルメントテストよりも高速に実行・実施ができます。
インストルメントテスト
実機やエミュレーター上で実行されるテストコードです。こちらは、Androidの機能に依存するUIまわりのテストや、外部機能などとの連携に対するテストコードとなります。より現実に近い環境でのテストとなるため、ユーザーストーリーを意識したテストに向いています。一方で、インストールなどのステップがビルド時に含まれるため、実行時間が比較的遅めになります。
今回は、ユニットテストの実装方法について解説します。
ユニットテストを実装する
ユニットテストの実装方法について、以下の流れで説明します。
- ライブラリの準備
- 実装
- その他
- Robolecticの紹介
ライブラリの準備
ユニットテストのテストコードを実装するためには以下をbuild.gradle
に追加が必要です。プロジェクトを新規作成する際にAndroid
Studioが自動で追加している場合がありますので、追加が必要か確認してください。
dependencies {
testImplementation("junit:junit:4.13.2")
}
実装
それでは実装していきましょう。
テスト対象
テスト対象は以下のクラス・メソッドとします。
class Sample {
fun test(input: Int?): Boolean {
if (input == null) {
throw IllegalArgumentException()
}
return input > 0
}
}
テスト観点
テスト対象となるメソッドは、以下の観点でテストコードを実装することができます。
true
が返される確認テストfalse
が返される確認テスト- 例外が投げられるテスト
上をベースに確認するテストコードを追加していきましょう。
テストクラスを追加する
テストを実装するため、テストクラスを実装します。テスト対象のクラスで
option
+ Enter
からCreate Test
を選択すればテストクラスを作成できます。SampleTest
という名前にすると、test
ディレクトリに以下のようなクラスが作成できると思います。
class SampleTest {
}
trueが返される確認テストを実装する
まずはtrue
が返されることのテストです。
@Test
fun testTrue() {
val sample = Sample()
val value = sample.test(1)
Assert.assertEquals(value, true)
}
以降の実装も同様ですが、テストメソッドを実装し@Test
アノテーションを付与します。
そして、実際にテストしたい内容を実装します。今回は、入力値に1
以上を指定した場合はtrue
が返却されるので、それを確認するためのテストを実装します。
falseが返される確認テストを実装する
次にfalse
が返されることのテストです。
@Test
fun testFalse() {
val sample = Sample()
val value = sample.test(0)
Assert.assertEquals(value, false)
}
同様に、false
が返却されるケースを実装します。入力値に0
以下を指定した場合はfalse
が返却されるので、それを確認するためのテストを実装します。
例外が投げられるテストを実装する
そして、例外が投げられることのテストです。
@Test(expected = IllegalArgumentException::class)
fun testException() {
val sample = Sample()
sample.test(null)
Assert.fail()
}
例外が発生するテストは@Testアノテーションのパラメータexpected
を指定します。そのパラメータには発生する例外のクラスを指定します。
また、例外が発生しなかった場合がテストがNGとなるように、例外がthrowされる直後のタイミングでAssert.fail()
を実装しておきます。
これにて、該当クラスメソッドのテストが実装できました。あとはテストを実行すれば期待した結果になるかを確認する処理が実行されます。
その他
ここまでテストコードの実装について解説しましたが、実は1点問題があります。ユニットテストは開発PC上で実行されますが、その都合により、AndroidSDKに含まれる機能を利用することができません。これが結構ネックになり、例えばよくある実装の一つであるFragment
のインスタンス生成メソッドは、Fragment
やそれに渡すBundle
がAndroidSDKに含まれるものなので、テストコードを実装することができません。
ではどうするかというと、一つはインストルメントテストで実装することです。実機やエミュレーター上でテストすることで、テストコードを実行することができます。
もう一つはRobolectric
を利用することです。Robolectric
はユニットテストでもAndroidSDKに含まれる機能を利用することができます。
Robolectricの紹介
今回は説明を省略しますが、公式サイトを紹介します。またRobolectric
の利用方法についても、後日解説を予定しています。
まとめ
今回はテストコード、特にユニットテストの実装方法について解説しました。テストコードやその実装の重要性は今後も高いものと予想されるので、今後もこれをテーマとした投稿をしていこうと考えていますので、よろしくお願いします。