Reputation: 2776
I am trying to use mockito in kotlin. I created the following test:
class HeroesDataSourceTest {
@Mock
lateinit var heroesRepository: HeroesRepository
@Mock
lateinit var params: PageKeyedDataSource.LoadInitialParams<Int>
@Mock
lateinit var callback: PageKeyedDataSource.LoadInitialCallback<Int, Heroes.Hero>
val hero = Heroes.Hero(1, "superman", "holasuperman", 1, null, null)
val results = Arrays.asList(hero)
val data = Heroes.Data(results)
val dataResult = Heroes.DataResult(data)
val compositeDisposable = CompositeDisposable()
lateinit var heroesDataSource: HeroesDataSource
private val heroesPublishSubject = PublishSubject.create<Heroes.DataResult>()
@Before
fun initTest(){
MockitoAnnotations.initMocks(this)
}
@Test
fun testLoadInitialSuccess(){
`when`(heroesRepository.getHeroes(ArgumentMatchers.anyInt())).thenReturn(heroesPublishSubject.singleOrError())
heroesDataSource = HeroesDataSource(heroesRepository, compositeDisposable)
val testObserver = TestObserver<Heroes.DataResult>()
heroesDataSource.loadInitial(params, callback)
heroesPublishSubject.onNext(dataResult)
testObserver.assertComplete()
}
}
But when I execute it in the line when(heroesRepository.getHeroes(ArgumentMatchers.anyInt())).thenReturn(heroesPublishSubject.singleOrError())
it just enter to getHeroes method instead of mocking it (and for sure since heroesRepository is not initialized because is mocket the method fails). I use this tons of times in java and it never gave me a single problem. What I have to do in kotlin to mock it properly?
EDIT
Here I put also HeroesRepository class
open class HeroesRepository {
val privateKey = "5009bb73066f50f127907511e70f691cd3f2bb2c"
val publicKey = "51ef4d355f513641b490a80d32503852"
val apiDataSource = DataModule.create()
val pageSize = 20
fun getHeroes(page: Int): Single<Heroes.DataResult> {
val now = Date().time.toString()
val hash = generateHash(now + privateKey + publicKey)
val offset: Int = page * pageSize
return apiDataSource.getHeroes(now, publicKey, hash, offset, pageSize)
}
fun generateHash(variable: String): String {
val md = MessageDigest.getInstance("MD5")
val digested = md.digest(variable.toByteArray())
return digested.joinToString("") {
String.format("%02x", it)
}
}
}
Upvotes: 10
Views: 16008
Reputation: 31
FWIW, the reason that the when
statement is just calling the actual function is because the function itself (getHeroes
) is not marked as open
.
So even though the class is non-final the method is final and not mocked.
Upvotes: 3
Reputation: 141
Mockito is not quite compatible with kotlin, you can use mockito-kotlin resource instead. Check out this reference: https://github.com/nhaarman/mockito-kotlin
You can easily mock objects like so:
val heroesRepository = mock<HeroesRepository>()
Then you can use it as you use mockito
Upvotes: 2
Reputation: 1576
Without adding another dependency, you can replace using the @Mock
annotation with a helper function somewhere:
inline fun <reified T> mock(): T =
Mockito.mock(T::class.java)
// To avoid having to use backticks for "when"
fun <T> whenever(methodCall: T): OngoingStubbing<T> =
Mockito.`when`(methodCall)
Then in your test:
val heroesRepository: HeroesRepository = mock()
@Test
fun yourTest() {
whenever(heroesRepository.getHeroes(ArgumentMatchers.anyInt()))
.thenReturn(heroesPublishSubject.singleOrError())
}
Like you had before. This should work, because you're not expecting Mockito to deal with @Mock lateinit var
, which it seems to be struggling with, and instead instantiating the mock yourself.
Upvotes: 15