I have the following code inside the presenter.
public class SignUpPresenter implements Presenter {
private CompositeDisposable disposables;
private View view;
@Inject public SignUpPresenter() {
}
public void setView(View view) {
this.view = view;
}
public void redirectToLogInScreenAfterOneSecond() {
disposables = RxUtil.initDisposables(disposables);
view.displaySuccessMessage();
Disposable disposable = Flowable.interval(1, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(aLong -> view.onRegistrationSuccessful(), view::handleError);
disposables.add(disposable);
}
@Override public void dispose() {
RxUtil.dispose(disposables);
}
public interface View extends Presenter.View {
void onRegistrationSuccessful();
void displaySuccessMessage();
}
}
Now, I want to write unit test for that method.
@RunWith(PowerMockRunner.class)
public class SignUpPresenterTest {
@Rule TrampolineSchedulerRule trampolineSchedulerRule = new TrampolineSchedulerRule();
@Mock SignUpPresenter.View view;
private SignUpPresenter presenter;
private TestScheduler testScheduler;
@Before public void setUp() {
testScheduler = new TestScheduler();
RxJavaPlugins.setComputationSchedulerHandler(scheduler -> testScheduler);
presenter = new SignUpPresenter();
presenter.setView(view);
}
@Test public void shouldDisplaySuccessMessage() {
testScheduler.advanceTimeTo(1, TimeUnit.SECONDS);
presenter.redirectToLogInScreenAfterOneSecond();
Mockito.verify(view).displaySuccessMessage();
Mockito.verify(view).onRegistrationSuccessful();
}
}
Here is the error that I get:
Wanted but not invoked:
view.onRegistrationSuccessful();
-> at com.test.presentation.signup.SignUpPresenterTest.shouldDisplaySuccessMessage(SignUpPresenterTest.java:36)
However, there were other interactions with this mock:
view.displaySuccessMessage();
-> at com.test.presentation.signup.SignUpPresenter.redirectToLogInScreenAfterOneSecond(SignUpPresenter.java:28)
Wanted but not invoked:
view.onRegistrationSuccessful();
-> at com.test.presentation.signup.SignUpPresenterTest.shouldDisplaySuccessMessage(SignUpPresenterTest.java:36)
However, there were other interactions with this mock:
view.displaySuccessMessage();
-> at com.test.presentation.signup.SignUpPresenter.redirectToLogInScreenAfterOneSecond(SignUpPresenter.java:28)
You have to move the time after the flow setup:
@Test public void shouldDisplaySuccessMessage() {
presenter.redirectToLogInScreenAfterOneSecond();
testScheduler.advanceTimeTo(1, TimeUnit.SECONDS);
Mockito.verify(view).displaySuccessMessage();
Mockito.verify(view).onRegistrationSuccessful();
}
Also you don't need that many operators after interval but use the mainThread scheduler directly:
Disposable disposable = Flowable.interval(1, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
.subscribe(aLong -> view.onRegistrationSuccessful(), view::handleError);
and replace the mainThread scheduler:
@Before public void setUp() {
testScheduler = new TestScheduler();
RxAndroidPlugins.setMainThreadSchedulerHandler(scheduler -> testScheduler);
presenter = new SignUpPresenter();
presenter.setView(view);
}