📘

Kotestでのユニットテスト - mockK編

2022/10/31に公開

はじめに

前回はKotestの基本構文についてまとめた記事を記載しました。
今回はこのKotestをサポートするライブラリについても記載していきます。

Kotestでのユニットテスト - Kotest基本構文編 -> 前回
Kotestでのユニットテスト - mockk編 -> 今回
Kotestでのユニットテスト - testcontainers編

mockK

モックとして扱える。テスト対象以外のオブジェクトを差し替えて、どのような振る舞いをするかを決めてあげることで、テスト対象外のオブジェクトが存在する場合に、モックに差し替えて動作内容を定義できます。

よく使うファンクション/アノテーション

  • every
    特定のモックインスタンスが呼ばれた時に指定した値を返却する
  • verify
    メソッドが指定した引数で呼び出されたかを確認できる
  • @MockK
    モックとしてインジェクションする
  • @SpyK
    メソッドの引数や呼び出し回数、戻り値などを検証する

mockK導入

前準備としては以下のライブラリを入れるだけです。

testImplementation("io.mockk:mockk:1.13.1")

テスト対象クラス

ユーザークラスを作成して、レポジトリ層でCRDできるメソッドを作成。実体クラスなどは割愛します

UserRepository.kt
@Repository
interface UserRepository : MongoRepository<User> {
}
UserService.kt
@Service
class UserService(
    private val userRepository: UserRepository
) : UserRepository {
    fun saveUser(user: User): User {
        return this.userRepository.save(user: User))
    }

    fun getUser(id: String): User {
        return this.userRepository.get(id) ?: throw IllegalArgumentException("User with id $id not found")
    }

    fun deleteUser(id: String) {
        this.userRepository.clear(id)
    }
}

テストクラス

UserServiceTest.kt
internal class UserServiceTest : FunSpec(){
    lateinit var userRepository: UserRepository
    lateinit var userService: UserService

    beforeTest {
        // mock作成
        userRepository = mockk()
        userService = UserService(userRepository)
    }

    init {
    	context("saveUser") {
	    context("正常系") {
    		//given
    		val randomId = UUID.randomUUID().toString();
    	        val testUser = User(id = randomId, name = "testUser1")
    		val expectedUser = User(testUser)

    		every { userRepository.saveUser(any()) } returns expectedUser

    		//when
    		val result = userService.create(user)

    		//then
    		result.should(expectedUser)

    		verify { userRepository.save(any()) }
    		confirmVerified(userRepository)
    	    }
	}
    }
}

まとめ

mockを使うことでDBの環境依存などが起きないので、外部依存を気にせず想定しているテストを簡単に確認ことができます。Javaだとmockitoというライブラリが有名かと思いますが、KotlinだとmockKがそのポジションのよう。テストケースを書く上で、使わない理由はないかなと感じています。
次回はtestcontainerというインメモリDBを使わない独立したテストを実行できるライブラリを紹介します。

Discussion