2
Help us understand the problem. What are the problem?

posted at

Mockitoでのユニットテストに入門してみた

Mockitoとは

Mockitoとは、Javaアプリケーション開発においてデファクトスタンダートになっているモックライブラリです。
ユニットテストを記述するする際、テスト対象が他のコンポーネントに依存している場合、その依存しているコンポーネントとそっくりな振る舞いをするテストダブル(影武者)を作成する必要があります。
自前でテストダブルを作成するのは大変ですが、Mockitoを使えば依存コンポーネントとテスト対象とのやりとりを簡単に実装することができます。
今回は、MockitoのKotlin向けラッパーアプリである Mockito-Kotlin を使用していきます。

テストダブルについて

テストダブルの役割は以下の5つです。

  • スタブ
  • モック
  • スパイ
  • フェイク
  • ダミー

今回は、特によく使われるスタブ・モック・スパイオブジェクトについて入門していきます。
スタブ: テスト対象に対して、事前定義した任意の値を与える
モック: テスト対象メソッド実行時に、テスト対象が依存コンポーネントに与える挙動を検証するためのテストダブル
スパイ:スタブの上位互換のようなもので、テスト対象に値を与えるのが主な責務
それぞれの役割は上記の通りです。正直、読んでいてもいまいち理解が追いつかなかったためとりあえず実際にコードを書いていきます。

テスト対象クラスと依存コンポーネントの作成

下記のように、天気予報を行うためのクラスとしてWeatherForecastを作成し、それに対してユニットテストを行なっていきます。
WeatherForecastshouldBringUmbrellaメソッドを持ち、依存先の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
    }
}

テストを実行し、結果を確認します。
期待通りにテストが通っていることが確認できました。
スクリーンショット 2022-01-06 15.56.54.png

今日はここまで!

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
2
Help us understand the problem. What are the problem?