我是编写测试和使用Mockito的新手。 我已经在Stackoverflow上阅读了类似的主题,并进行了建议的更改,确保所考虑的类/接口/方法是开放的。
模拟构造函数注入的依赖项
这是我到目前为止所做的测试
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>
}
感谢所有帮助。
答案 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();