Mockito想要但没有被调用

时间:2016-11-18 12:44:24

标签: android testing mockito rx-java kotlin

我是编写测试和使用Mockito的新手。 我已经在Stackoverflow上阅读了类似的主题,并进行了建议的更改,确保所考虑的类/接口/方法是开放的。

  

I tried to follow this

模拟构造函数注入的依赖项

这是我到目前为止所做的测试

class RegistrationPresenterTest {
@Test
fun testRegisterSuccess() {
    val mockService = mock<IHerokuInteractor>()
    val mockLocal = mock<ILocalStorageInteractor>()
    val mockView = mock<RegisterView>()
    val mockRegistrationResponse = HerokuRegisterResponse("hash")
    val mockPair = ImeiPair("imei","hash")
    val presenter = RegisterPresenterImpl(mockLocal,mockService)

   whenever(mockService.register(any())).thenReturn(Observable.just(mockRegistrationResponse))
    whenever(mockLocal.clearPreferences()).thenReturn(Observable.just(true))
    whenever(mockLocal.putImeiPair(any())).thenReturn(Observable.just(true))
    //whenever(presenter.writeImeiPairLocally(any())) How do I specify parameters since it uses a parameter from the register method?

    presenter.bindView(mockView)
    presenter.register("imei","male")

    verify(mockService, times(1)).register(any())
    verify(mockLocal,times(1)).clearPreferences()
    verify(mockLocal,times(1)).putImeiPair(any())
    verify(mockView,times(1)).moveToMain()
}

但我一直得到的回应是

Wanted but not invoked:
registerPresenterImpl.writeImeiPairLocally(
<any com.company.appname.model.ImeiPair>
);

Actually, there were zero interactions with this mock.

即使我在测试中没有提到这种方法,我也得到了这个回应。 这是我的演示者注册方法。我改变了类/接口&amp;涉及开放的方法(kotlin)。我相信覆盖方法在kotlin中是开放的。

 open class RegisterPresenterImpl @Inject constructor(val localStorage : ILocalStorageInteractor, var herokuService : IHerokuInteractor)

 override fun register(imei : String, gender : String){
    subscription = herokuService.register(RegisterObject(imei,gender)).subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread()).subscribe(
            {
                registrationResult ->
                Log.d(TAG,"${registrationResult}")
                if(registrationResult.imei_hash != null){
                    writeImeiPairLocally(ImeiPair(imei,registrationResult.imei_hash))
                }
                else{
                    Log.e(TAG,"User already exists")
                }
            },
            {
                errorResponse -> Log.e(TAG,"Could not register user ${errorResponse.message}")
            }
    )
    addSubscription(subscription)
}

类似
open fun writeImeiPairLocally(pair : ImeiPair){
    subscription = localStorage.clearPreferences().flatMap {
        cleared -> localStorage.putImeiPair(pair)}.subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread()).subscribe(
            {

                booleanResult -> view?.moveToMain()
            },
            {
                errorResponse -> Log.e(TAG,"Could not write ImeiPair to SharedPreferences ${errorResponse.message}")
            }
    )
    addSubscription(subscription)

}

这是接口

open interface ILocalStorageInteractor : ILocalStorage{
   fun getImeiPair() : Observable<ImeiPair>
   fun putImeiPair(pair: ImeiPair) : Observable<Boolean>
}

open interface ILocalStorage {
   fun clearPreferences() : Observable<Boolean>
}

感谢所有帮助。

1 个答案:

答案 0 :(得分:1)

如果您使用普通的jUnit,则AndroidSchedulers.mainThread()为空。这就是为什么不调用onNext的原因。

您需要使用以下内容覆盖setUp()方法中的调度程序:

    RxAndroidPlugins.getInstance().registerSchedulersHook(new RxAndroidSchedulersHook() {
        @Override
        public Scheduler getMainThreadScheduler() {
            return Schedulers.immediate(); // or .test()
        }
    });

为了避免测试中的并发性,我建议像这样覆盖Schedulers.io()

    RxJavaHooks.setOnIOScheduler(scheduler1 -> Schedulers.immediate());

如果您要使用TestScheduler,请不要忘记拨打TestScheduler.triggerActions()方法。

另外,请不要忘记在tearDown()中取消注册调度程序,如下所示:

    RxJavaHooks.reset();
    RxAndroidPlugins.getInstance().reset();
    AndroidSchedulers.reset();
    Schedulers.reset();