Mockitoとは
Mockitoとは、Javaアプリケーション開発においてデファクトスタンダートになっているモックライブラリです。
ユニットテストを記述するする際、テスト対象が他のコンポーネントに依存している場合、その依存しているコンポーネントとそっくりな振る舞いをするテストダブル(影武者)を作成する必要があります。
自前でテストダブルを作成するのは大変ですが、Mockitoを使えば依存コンポーネントとテスト対象とのやりとりを簡単に実装することができます。
今回は、MockitoのKotlin向けラッパーアプリである Mockito-Kotlin を使用していきます。
テストダブルについて
テストダブルの役割は以下の5つです。
- スタブ
- モック
- スパイ
- フェイク
- ダミー
今回は、特によく使われるスタブ・モック・スパイオブジェクトについて入門していきます。
スタブ: テスト対象に対して、事前定義した任意の値を与える
モック: テスト対象メソッド実行時に、テスト対象が依存コンポーネントに与える挙動を検証するためのテストダブル
スパイ:スタブの上位互換のようなもので、テスト対象に値を与えるのが主な責務
それぞれの役割は上記の通りです。正直、読んでいてもいまいち理解が追いつかなかったためとりあえず実際にコードを書いていきます。
テスト対象クラスと依存コンポーネントの作成
下記のように、天気予報を行うためのクラスとしてWeatherForecast
を作成し、それに対してユニットテストを行なっていきます。
WeatherForecast
はshouldBringUmbrella
メソッドを持ち、依存先のSatellite#getWeather()
メソッドで取得した天候をもとに傘が必要かどうかの真偽値を返します。
class WeatherForecast(val satellite: Satellite) {
fun shouldBringUmbrella(): Boolean {
val weather = satellite.getWeather()
return when (weather) {
Weather.SUNNY, Weather.CLOUDY -> false
Weather.RAINY -> true
}
}
}
open class Satellite {
open fun getWeather(): Weather {
return Weather.SUNNY
}
}
enum class Weather {
SUNNY, CLOUDY, RAINY
}
モックの生成
WeatherForecast
のテストクラスであるWeatherForecastTest
クラスを生成します。
WeatherForecast
クラスはSatellite
クラスの挙動に依存しているため、テストするにはSatellite`クラスのモックが必要となります。
Mockitoを使うと、下記のようにモックオブジェクトの作成ができます。
class WeatherForecastTest {
@Mock
lateinit var satelite: Satellite
@Before
fun setup() {
MockitoAnnotations.openMocks(this)
}
}
モックオブジェクトに@Mockアノテーションをつけ、MockitoAnnotations.openMocks
を呼ぶことでテスト実行時にフィールドにモックオブジェクトが挿入されます。
スタブメソッドの設定
上記で作成したSatellite
のモックオブジェクトに対して、スタブメソッドを設定します。
whenever (satelite.getWeather()).thenReturn(Weather.SUNNY)
今回は常にSunnyを返すように設定しました。
以上で、テストダブルの設定は終了です。
テストコードの記述と実行
テストダブルの設定が完了したので、実際にテストコードを書いていきます
今回は、satelite.getWeather()
が常にSunnyを返すため、テスト対象クラスのshouldBringUmbrella
はfalseを返すことが期待値です。
下記のようなテストコードを記述し、実行していきます。
class WeatherForecastTest {
@Mock
lateinit var satelite: Satellite
lateinit var target: WeatherForecast
@Before
fun setup() {
MockitoAnnotations.openMocks(this)
whenever(satelite.getWeather()).thenReturn(Weather.SUNNY)
target = WeatherForecast(satelite)
}
@Test
fun shouldBringUmbrella_givenSunny_returnFalse() {
val actual = target.shouldBringUmbrella()
assertThat(actual).isFalse
}
}
テストを実行し、結果を確認します。
期待通りにテストが通っていることが確認できました。
今日はここまで!