📘
Kotestでのユニットテスト - mockK編
はじめに
前回は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