sockeqwe / mosby

A Model-View-Presenter / Model-View-Intent library for modern Android apps
http://hannesdorfmann.com/mosby/
Apache License 2.0
5.49k stars 841 forks source link

Unit Test freezes when PresenterTest emmits less ViewState values than expected by the ViewRobot #237

Closed regmoraes closed 7 years ago

regmoraes commented 7 years ago

Mosby Version mosby3:mvi:3.0.2

Steps to reproduce the behavior or link to a sample repository

  1. Create a Unit Test for the MviBasePresenter based on this sample.

  2. On this test, make the Presenter emmit less ViewState items ( but not null ) than the expected by the ViewRobot.

Expected/Ideal behavior

The test should fail if the Presenter emmits less ViewState values than expected

Actual behavior

The test freezes, therefore it doesn't terminate with failure nor success.

Analysis

If we look at the assertViewStateRendered() method of the HomeViewRobot class we can see that it actually only checks if the number of emmited ViewStates is null or greater than the expected

if (expectedHomeViewStates == null) {
  throw new NullPointerException("expectedHomeViewStates == null");
}

int eventsCount = expectedHomeViewStates.length;
renderEventSubject.take(eventsCount).blockingSubscribe();

   //(...)

if (renderEventSubject.getValues().length > eventsCount) {
  Assert.fail("Expected to wait for "
      + eventsCount
      + ", but there were "
      + renderEventSubject.getValues().length
      + " Events in total, which is more than expected: "
      + arrayToString(renderEventSubject.getValues()));
}

Assert.assertEquals(Arrays.asList(expectedHomeViewStates), renderEvents);

Proposed Solution

To solve this problem and be able to handle the cases were the emmited ViewStates are smaller than expected, I added a Observable.timeout(Long, TimeUnit)call to the renderEventsSubject so it will throw a TimeoutException if it take more than Long to emmit the expected items.

/* 
 * Wait for 10 seconds to receive the expected ViewStates
 * 
 * Since this is a kind of Halting Problem, it will be diffycult to set an ideal timeout
 */
 renderEventSubject.take(eventsCount).timeout(10, TimeUnit.SECONDS).blockingSubscribe();
sockeqwe commented 7 years ago

Good Point! I have added timeout(), thanks!