使用 DisposableObserver 测试 Presenter
Testing Presenter with DisposableObserver
我正在开发一个 Android 应用程序,试图遵循 Clean Architecture / MVP 指南。
我目前正在为我的演示者编写单元测试,但我坚持调用 Interactor/UseCase,它采用 DisposableObserver 作为参数。
我想测试的是,当交互器调用 OnNext 或 OnError 时调用的行为是否正确(hide/show 加载指示器...)。
我不知道如何在我的用例中 'mock' Observable 的行为,因为它是在调用 execute() 方法时使用受保护的方法构建的。
下面是部分代码:
主持人
@ConfigPersistent
public class ContentPresenter extends BasePresenter<ContentContract.View> implements ContentContract.Presenter {
@Inject
GetContent mGetContentUseCase;
@Inject
ContentViewModelMapper mContentViewModelMapper;
@Inject
public ContentPresenter() {
}
@Override
public void fetchContent(long contentId) {
getMvpView().showProgress();
mGetContentUseCase.execute(contentId, new ContentObserver());
}
private final class ContentObserver extends DisposableObserver<Content> {
@Override
public void onNext(Content content) {
getMvpView().hideProgress();
getMvpView().showContentInfo(mContentViewModelMapper.map2(content));
}
@Override
public void onError(Throwable e) {
getMvpView().hideProgress();
Timber.e(e.getMessage());
}
@Override
public void onComplete() {
getMvpView().hideProgress();
}
}
}
Interactor/UseCase
public class GetContent extends UseCaseObservableWithParameter<Long, Content, Repository> {
@Inject
public GetContent(Repository repository,
@Named("Thread") Scheduler threadScheduler,
@Named("PostExecution") Scheduler postExecutionScheduler) {
super(repository, threadScheduler, postExecutionScheduler);
}
@Override
protected Observable<Content> buildObservable(Long id) {
return repository.getContentById(id);
}
}
基本用例
public abstract class UseCaseObservableWithParameter<REQUEST_DATA, RESPONSE_DATA, REPOSITORY> extends UseCase<Observable<RESPONSE_DATA>, REQUEST_DATA, REPOSITORY> {
public UseCaseObservableWithParameter(REPOSITORY repository, Scheduler threadScheduler, Scheduler postExecutionScheduler) {
super(repository, threadScheduler, postExecutionScheduler);
}
protected abstract Observable<RESPONSE_DATA> buildObservable(REQUEST_DATA requestData);
public void execute(REQUEST_DATA requestData, DisposableObserver<RESPONSE_DATA> useCaseSubscriber) {
this.disposable.clear();
this.disposable.add(
this.buildObservable(requestData)
.subscribeOn(threadScheduler)
.observeOn(postExecutionScheduler)
.subscribeWith(useCaseSubscriber)
);
}
}
睡了一觉后,我想到了这个:
@Test
@SuppressWarnings("unchecked")
public void testShowContents() {
doAnswer((i) -> {
// Do stuff with i.getArguments() here
DisposableObserver<Content> d = i.getArgument(1);
Observable.just(mock(Content.class)).subscribeWith(d);
return null;
})
.when(mGetContentUseCase)
.execute(eq(AppTestData.TEST_LONG_ID_1), any(DisposableObserver.class));
contentPresenter.fetchContent(AppTestData.TEST_LONG_ID_1);
Mockito.verify(view, Mockito.times(1)).showContentInfo(Mockito.any());
InOrder orderVerifier = Mockito.inOrder(view);
orderVerifier.verify(view).showProgress();
orderVerifier.verify(view).hideProgress();
orderVerifier.verify(view).showContentInfo(any());
}
@Test
@SuppressWarnings("unchecked")
public void testShowContentsError() {
doAnswer((i) -> {
// Do stuff with i.getArguments() here
DisposableObserver<Content> d = i.getArgument(1);
Observable.<Content>error(new Throwable()).subscribeWith(d);
return null;
})
.when(mGetContentUseCase)
.execute(eq(AppTestData.TEST_LONG_ID_1), any(DisposableObserver.class));
contentPresenter.fetchContent(AppTestData.TEST_LONG_ID_1);
Mockito.verify(view, Mockito.times(1)).showErrorMessage(Mockito.any());
InOrder orderVerifier = Mockito.inOrder(view);
orderVerifier.verify(view).showProgress();
orderVerifier.verify(view).hideProgress();
orderVerifier.verify(view).showErrorMessage(any());
}
我正在开发一个 Android 应用程序,试图遵循 Clean Architecture / MVP 指南。
我目前正在为我的演示者编写单元测试,但我坚持调用 Interactor/UseCase,它采用 DisposableObserver 作为参数。
我想测试的是,当交互器调用 OnNext 或 OnError 时调用的行为是否正确(hide/show 加载指示器...)。
我不知道如何在我的用例中 'mock' Observable 的行为,因为它是在调用 execute() 方法时使用受保护的方法构建的。
下面是部分代码:
主持人
@ConfigPersistent
public class ContentPresenter extends BasePresenter<ContentContract.View> implements ContentContract.Presenter {
@Inject
GetContent mGetContentUseCase;
@Inject
ContentViewModelMapper mContentViewModelMapper;
@Inject
public ContentPresenter() {
}
@Override
public void fetchContent(long contentId) {
getMvpView().showProgress();
mGetContentUseCase.execute(contentId, new ContentObserver());
}
private final class ContentObserver extends DisposableObserver<Content> {
@Override
public void onNext(Content content) {
getMvpView().hideProgress();
getMvpView().showContentInfo(mContentViewModelMapper.map2(content));
}
@Override
public void onError(Throwable e) {
getMvpView().hideProgress();
Timber.e(e.getMessage());
}
@Override
public void onComplete() {
getMvpView().hideProgress();
}
}
}
Interactor/UseCase
public class GetContent extends UseCaseObservableWithParameter<Long, Content, Repository> {
@Inject
public GetContent(Repository repository,
@Named("Thread") Scheduler threadScheduler,
@Named("PostExecution") Scheduler postExecutionScheduler) {
super(repository, threadScheduler, postExecutionScheduler);
}
@Override
protected Observable<Content> buildObservable(Long id) {
return repository.getContentById(id);
}
}
基本用例
public abstract class UseCaseObservableWithParameter<REQUEST_DATA, RESPONSE_DATA, REPOSITORY> extends UseCase<Observable<RESPONSE_DATA>, REQUEST_DATA, REPOSITORY> {
public UseCaseObservableWithParameter(REPOSITORY repository, Scheduler threadScheduler, Scheduler postExecutionScheduler) {
super(repository, threadScheduler, postExecutionScheduler);
}
protected abstract Observable<RESPONSE_DATA> buildObservable(REQUEST_DATA requestData);
public void execute(REQUEST_DATA requestData, DisposableObserver<RESPONSE_DATA> useCaseSubscriber) {
this.disposable.clear();
this.disposable.add(
this.buildObservable(requestData)
.subscribeOn(threadScheduler)
.observeOn(postExecutionScheduler)
.subscribeWith(useCaseSubscriber)
);
}
}
睡了一觉后,我想到了这个:
@Test
@SuppressWarnings("unchecked")
public void testShowContents() {
doAnswer((i) -> {
// Do stuff with i.getArguments() here
DisposableObserver<Content> d = i.getArgument(1);
Observable.just(mock(Content.class)).subscribeWith(d);
return null;
})
.when(mGetContentUseCase)
.execute(eq(AppTestData.TEST_LONG_ID_1), any(DisposableObserver.class));
contentPresenter.fetchContent(AppTestData.TEST_LONG_ID_1);
Mockito.verify(view, Mockito.times(1)).showContentInfo(Mockito.any());
InOrder orderVerifier = Mockito.inOrder(view);
orderVerifier.verify(view).showProgress();
orderVerifier.verify(view).hideProgress();
orderVerifier.verify(view).showContentInfo(any());
}
@Test
@SuppressWarnings("unchecked")
public void testShowContentsError() {
doAnswer((i) -> {
// Do stuff with i.getArguments() here
DisposableObserver<Content> d = i.getArgument(1);
Observable.<Content>error(new Throwable()).subscribeWith(d);
return null;
})
.when(mGetContentUseCase)
.execute(eq(AppTestData.TEST_LONG_ID_1), any(DisposableObserver.class));
contentPresenter.fetchContent(AppTestData.TEST_LONG_ID_1);
Mockito.verify(view, Mockito.times(1)).showErrorMessage(Mockito.any());
InOrder orderVerifier = Mockito.inOrder(view);
orderVerifier.verify(view).showProgress();
orderVerifier.verify(view).hideProgress();
orderVerifier.verify(view).showErrorMessage(any());
}