Mocking y Kotest
Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
Kotest no tiene funciones de mocking integradas. ¡Pero puedes integrar fácilmente tu biblioteca de mocking favorita!
Tomemos como ejemplo mockk:
class MyTest : FunSpec({
val repository = mockk<MyRepository>()
val target = MyService(repository)
test("Saves to repository") {
every { repository.save(any()) } just Runs
target.save(MyDataClass("a"))
verify(exactly = 1) { repository.save(MyDataClass("a")) }
}
})
Este ejemplo funciona como se espera, pero ¿qué pasa si añadimos más tests que usen ese mockk?
class MyTest : FunSpec({
val repository = mockk<MyRepository>()
val target = MyService(repository)
test("Saves to repository") {
every { repository.save(any()) } just Runs
target.save(MyDataClass("a"))
verify(exactly = 1) { repository.save(MyDataClass("a")) }
}
test("Saves to repository as well") {
every { repository.save(any()) } just Runs
target.save(MyDataClass("a"))
verify(exactly = 1) { repository.save(MyDataClass("a")) }
}
})
¡El fragmento anterior causará una excepción!
Se encontraron 2 llamadas coincidentes, pero se necesitan al menos 1 y como máximo 1 llamadas
Esto ocurre porque los mocks no se reinician entre invocaciones. Por defecto, Kotest aísla los tests creando una única instancia del spec para ejecutar todas las pruebas.
Esto provoca que se reutilicen los mocks. ¿Pero cómo podemos solucionarlo?
Opción 1 - Configurar mocks antes de los tests
class MyTest : FunSpec({
lateinit var repository: MyRepository
lateinit var target: MyService
beforeTest {
repository = mockk()
target = MyService(repository)
}
test("Saves to repository") {
// ...
}
test("Saves to repository as well") {
// ...
}
})
Opción 2 - Reiniciar mocks después de los tests
class MyTest : FunSpec({
val repository = mockk<MyRepository>()
val target = MyService(repository)
afterTest {
clearMocks(repository)
}
test("Saves to repository") {
// ...
}
test("Saves to repository as well") {
// ...
}
})
Posicionamiento de los listeners
Como con cualquier función que se ejecute dentro de la definición del Spec, puedes colocar los listeners al final
class MyTest : FunSpec({
val repository = mockk<MyRepository>()
val target = MyService(repository)
test("Saves to repository") {
// ...
}
test("Saves to repository as well") {
// ...
}
afterTest {
clearMocks(repository) // <---- End of file, better readability
}
})
Opción 3 - Ajustar el IsolationMode
Dependiendo del uso, jugar con el IsolationMode para un Spec dado también puede ser una buena opción. Visita la documentación del isolation mode si quieres entenderlo mejor.
class MyTest : FunSpec({
val repository = mockk<MyRepository>()
val target = MyService(repository)
test("Saves to repository") {
// ...
}
test("Saves to repository as well") {
// ...
}
isolationMode = IsolationMode.InstancePerTest
})