0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

KotlinのRandomをmockにする

Posted at

この記事の内容

自作のアプリでkotlin.random.Random を使った関数のテストを書きたくなったときに意外と苦労した備忘録。

Spring Bootを利用したwebアプリケーションで、テストコードにはJunit、Mockito-Kotlinなどを使用しています。

例えばこんなコード

@Service
class SomeService {
    // この関数をテストする
    fun someFunction(): Int {
        // 1から100までの乱数を生成
        val randomValue = Random.nextInt(1, 101)

        // ゾロ目の時だけ10倍して返す
        return if(randomValue % 11 == 0) {
            randomValue * 10
        } else {
            randomValue
        }
    }
}

テストを書こう

この関数のテストで、以下の点を確かめます。

  • 1から100までの乱数を生成していること(すなわちRandom.nextInt(1, 101)を呼び出していること)
  • 11の倍数のときには10倍の値を返すこと

Random のテストのためにシードを固定ような方法もありますが、mockを使えば解決しそう、ということで以下のようなコードを書きました。

class SomeServiceTest {
    @Mock
    private lateinit var random: Random
    @InjectMocks
    private lateinit var someService: SomeService

    @Test
    fun testSomeFunction() {
        whenever(random.nextInt(1, 101)).thenReturn(11)

        val actual = someService.someFunction()

        verify(random).nextInt(1, 101)  // ①
        assertThat(actual).isEqualTo(110)  // ②
    }

     // それ以外のテストケースは省略
}

これでテストケースをパスすると思いきや、①では、random.nextInt(1, 101) は呼び出されていないことになっており、②のactualの値はwhenever ~ thenReturnで設定したものと異なる値が入っていました。

何が問題か

Random.nextInt()がstaticな関数であったため、mockと置き換えられていなかったようです。

というわけで、Serviceの実装部分でDIを使うように書き直しました。

まず、Beanを登録。

config.kt
@Configuration
class Config {
    @Bean
    fun random(): Random = Random.Default
}

そして、ServiceクラスではこのBeanを使う

@Service
class SomeService {
    @Autowired
    private lateinit var random: Random

    fun someFunction(): Int {
        // クラスのフィールドのrandomを使うように修正
        val randomValue = random.nextInt(1, 101)

        return if(randomValue % 11 == 0) {
            randomValue * 10
        } else {
            randomValue
        }
    }
}

これで先ほど書いたテストコードをパスするようになりました。

まとめ

他にも mockStatic を利用する方法があるようです。今回はverify(呼び出し回数のテスト)がうまく動かなくてやめました。
テストのために実装を変える形ではあるので、やや不満があります。良い方法をご存知の方は教えていただけると喜びます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?