Estoy tratando de usar mockito en kotlin. Creé la siguiente prueba:
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() } } Pero cuando lo ejecuto en la línea when(heroesRepository.getHeroes(ArgumentMatchers.anyInt())).thenReturn(heroesPublishSubject.singleOrError()) simplemente ingresa al método getHeroes en lugar de burlarse de él (y seguro que heroesRepository no está inicializado porque es falso el método falla). Lo uso muchas veces en Java y nunca me dio un solo problema. ¿Qué tengo que hacer en kotlin para simularlo correctamente?
EDITAR
Aquí pongo también la clase HeroesRepository
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) } } }Sin agregar otra dependencia, puede reemplazar el uso de la anotación @Mock con una función auxiliar en algún lugar:
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)Luego en tu prueba:
val heroesRepository: HeroesRepository = mock() @Test fun yourTest() { whenever(heroesRepository.getHeroes(ArgumentMatchers.anyInt())) .thenReturn(heroesPublishSubject.singleOrError()) } Como lo habías hecho antes. Esto debería funcionar, porque no espera que Mockito se ocupe de @Mock lateinit var , con lo que parece tener problemas, sino que cree una instancia del simulacro usted mismo.
Mockito no es del todo compatible con kotlin, puede usar el recurso mockito-kotlin en su lugar. Consulte esta referencia: https://github.com/nhaarman/mockito-kotlin
Puedes burlarte fácilmente de objetos así:
val heroesRepository = mock<HeroesRepository>()Entonces puedes usarlo como usas mockito
FWIW, la razón por la que la instrucción when solo está llamando a la función real es porque la función en sí ( getHeroes ) no está marcada como open .
Entonces, aunque la clase no es final, el método es final y no se burla.