Prueba de la aplicación Android Kotlin: Mockito con Dagger inyecta nulo

Estoy aprendiendo testings en Android con Mockito y Robolectric. Creé una aplicación muy simple en Kotlin con RxJava y Dagger2, utilizando Clean Architecture. Todo funciona bien en el dispositivo, pero no puedo hacer que pase mi testing. Aquí está mi LoginPresenterTest:

@RunWith(RobolectricGradleTestRunner::class) @Config(constants = BuildConfig::class) public class LoginPresenterTest { private lateinit var loginPresenter: LoginPresenter @Rule @JvmField public val mockitoRule: MockitoRule = MockitoJUnit.rule() @Mock private lateinit var mockContext: Context @Mock private lateinit var mockLoginUseCase: LoginUseCase @Mock private lateinit var mockLoginView: LoginView @Mock private lateinit var mockCnetworkingentialsUseCase: GetCnetworkingentials @Before public fun setUp() { loginPresenter = LoginPresenter(mockCnetworkingentialsUseCase, mockLoginUseCase) loginPresenter.view = mockLoginView } @Test public fun testLoginPresenterResume(){ given(mockLoginView.context()).willReturn(mockContext) loginPresenter.resume(); } } 

Constructor de LoginPresenter:

 class LoginPresenter @Inject constructor(@Named("getCnetworkingentials") val getCnetworkingentials: UseCase, @Named("loginUseCase") val loginUseCase: LoginUseCase) : Presenter<LoginView> 

en loginPresenter.resume() tengo:

 override fun resume() { getCnetworkingentials.execute(GetCnetworkingentialsSubscriber() as DefaultSubscriber<in Any>) } 

Y, finalmente, GetCnetworkingentials:

 open class GetCnetworkingentials @Inject constructor(var userRepository: UserRepository, threadExecutor: Executor, postExecutionThread: PostExecutionThread): UseCase(threadExecutor, postExecutionThread) { override fun buildUseCaseObservable(): Observable<Cnetworkingentials> = userRepository.cnetworkingentials() } 

El problema es que cada campo en GetCnetworkingentials es nulo. Creo que echo de less algo (tomé el patrón de este proyecto: https://github.com/android10/Android-CleanArchitecture ), pero no puedo encontrar de qué se trata. ¿Alguien sabe qué puede causar esto?

    Está utilizando una instancia simulada de GetCnetworkingentials ( @Mock var mockCnetworkingentialsUseCase: GetCnetworkingentials ) es por eso que tiene s null en sus campos. Rara vez es una buena idea burlarse de todo, aparte de la class principal bajo testing ( LoginPresenter ). Una forma de pensar en esto es dividir las dependencies en pares e internos . Reescribiría la testing a algo así como:

     inline fun <reified T:Any> mock() : T = Mockito.mock(T::class.java) @RunWith(RobolectricGradleTestRunner::class) @Config(constants = BuildConfig::class) public class LoginPresenterTest { val mockContext:Context = mock() val mockLoginView:LoginView = mock().apply { given(this.context()).willReturn(mockContext) } val userRepository:UserRepository = mock() // or some in memory implementation val cnetworkingentials = GetCnetworkingentials(userRepository, testThreadExecutor, testPostThreadExecutor) // yes, let's use real GetCnetworkingentials implementation val loginUseCase = LoginUseCase() // and a real LoginUseCase if possible val loginPresenter = LoginPresenter(cnetworkingentials, loginUseCase).apply { view = mockLoginView } @Test public fun testLoginPresenterResume(){ given(mockLoginView.context()).willReturn(mockContext) loginPresenter.resume(); // do actual assertions as what should happen } } 

    Como de costumbre, debes pensar en lo que estás probando. El scope de la testing no tiene que estar limitado a una sola class. A menudo es más fácil pensar en las características que estás probando en lugar de las classs (como en BDD ). Sobre todo, trate de evitar testings como esta , que en mi opinión agrega muy poco valor como una testing de regresión, pero aún impide la refactorización.

    PD. Roboeléctrico añade funciones auxiliares para el context