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?

More than 3 years have passed since last update.

KotlinでMockolo風のモック生成ライブラリを作ってみた

Last updated at Posted at 2020-11-23

作ってみたライブラリ

KotlinでMockolo風のライブラリがあるか調べてみたが、なさそうだったので自分で作ってみた1。名前は、kotlin-simple-mockとした。
interfaceに@Mockableというアノテーションを付けると、そのMockを生成する。

GitHub
https://github.com/KamikazeZirou/kotlin-simple-mock

なぜライブラリを作ったか

普段、Kotlinでテストコードを書くときにmockKやMockitoを使っている。
これらのライブラリに大体満足しているのだが、一つだけ不満がある。

複雑でもなく、数も少ないテストケースを実行するときに、もっさり感があることだ。

mockKだと1秒以上かかることもざらである。Mockitoはmockより格段に高速だが、それでも100ms以上かかることはざらである。

同じような条件で、自前でテストモックを作ってテストを実行させると、100msもかからなかった。

高速なテスト実行を重視するのであれば、自前mockを作れば良いということだ。だが、mockをいちいち実装するのは面倒だ。

そこで思いあったのが、SwiftのMockoloというモック生成ライブラリだ。MockoloはProtocol2から単純なmockを高速に生成するライブラリだ。Kotlinでもこの方式のライブラリがあれば、Mockを自動生成しつつ、テストの実行時間を高速にできると考えた。

ざっくりとした使い方

Step 1. Mockを生成したいinterfaceを指定する

Mockを生成したいinterfaceに@Mockableを付与する。


import mock.simple.kotlin.Mockable

@Mockable
interface Hello {
    fun add(a: Int, b: Int): Int
    var num: Int
}

Step 2. ソースコードをビルドして、Mockを生成する

Mock生成にkaptを利用しているので、kaptを実行させるためにソースコードをビルドする。以下のようなコードがMockHello.ktとして生成される。

class MockHello : Hello {
  public var addHandler: ((a: Int, b: Int) -> Int)? = null
  public var addCallCount: Int = 0
  public var addArgValues: MutableList<List<*>> = mutableListOf()
  public override fun add(a: Int, b: Int): Int {
    addCallCount += 1
    addArgValues.add(listOf(a,b))
    return addHandler!!(a,b)
  }

  public var underlyingNum: Int? = null
  public var numSetCallCount: Int = 0
  public override var num: Int
    get() = underlyingNum!!
    set(newValue) {
      underlyingNum = newValue
      numSetCallCount += 1
    }
}

Step 3. テストコードを書く

class HelloTest {
    @Test
    fun add() {
        // <メソッド名>FuncHandlerに関数を設定することで処理を差し替える
        val mock = MockHello()
        mock.addHandler = { a, b ->
            a + b
        }

        val result = mock.add(1, 2)

        assertEquals(3, result)
        // <メソッド名>CallCountという変数で、メソッドの呼び出し回数を取得する
        assertEquals(1, mock.addCallCount)
        // <メソッド名>FuncArgValuesという変数で、メソッドが呼ばれたときの引数を取得する
        assertEquals(listOf(1, 2), mock.addArgValues.first())
    }
}

Mockライブラリのテスト実行時間の比較

https://qiita.com/zigenin/items/75679e1988b72dd728ac
(この記事の自前Mock = このライブラリで生成したMock)

最後に

ライブラリを作ったり、この記事をここまで書いておいてなんだが、Kotlinでテスト速度を追求したい人はMockitoを使うのが良いと思う。

初回のテスト実行時間はこのライブラリで短くなるが、kaptによってビルド時間が長くなることを考慮すると、Mockito使った方が良さそう3

  1. ある用途のサービスやライブラリを誰も作っていない時、本当に新規な時と考え方の筋が悪い時がある。後述するが、このライブラリは後者のケースだと思う。単に作っておしまいで済ませるのも勿体なく感じたので、この記事を書いた。

  2. Kotlinのinterfaceに相当する。

  3. このライブラリによるビルド時間の増加量は検証していない。

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?