Let’s consider the following system under test:
class Repository {
fun getAll(): List<String> {
// retrieve or create list of strings somehow
}
}
// return only entries containing letter "g"
class UseCase(private val repository: Repository) {
fun execute(): List<String> {
return repository.getAll().filter { it.contains("g") }
}
}
And following test method:
class UseCaseTest {
@Test
fun `it should return elements containing letter g`() {
val mockRepository: Repository = mock {
on { getAll() } doReturn listOf("kotlin", "testing", "blog")
}
val useCase = UseCase(
repository = mockRepository
)
val result = useCase.execute()
result.size shouldBe 2
}
}
if you are unsure how to use Mockito with Kotlin, check https://androidpro.io/using-mockito-in-kotlin-projects/
After running this test it is likely that you will encounter the following error:
Cannot mock/spy class com.kotlintesting.edu.Repository
Mockito cannot mock/spy because :
- final class
- Classes marked as “final” should not be extended
- Kotlin default modifier translates to “final” in Java
- Classes in Kotlin are “final” unless specified otherwise (open class, abstract class)
- Mocking frameworks usually extend your class to do something with implementation details.
While the preferred solution is to use an interface for dependency, there is solution that will allow us to mock final classes with Mockito. To enable mocking final classes, configure MockMaker:
Configure MockMaker
In app/src/test/resources/mockito-extensions add file:
org.mockito.plugins.MockMaker
With contents:
mock-maker-inline
org.mockito.plugins.MockMaker content
If you add this file in proper place and run tests again, class Repository will be properly mocked and error Mockito cannot mock/spy because your class is final class will be there no more.