/* * Copyright 2017 Hannes Dorfmann. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.hannesdorfmann.mosby3.sample.mvi.view.home; import io.reactivex.Observable; import io.reactivex.subjects.PublishSubject; import io.reactivex.subjects.ReplaySubject; import java.util.Arrays; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; import org.junit.Assert; /** * This class is responsible to drive the HomeView. * Internally this creates a {@link HomeView} and attaches it to the {@link HomePresenter} * and offers public API to fire view intents and to check for expected view.render() events. * * <p> * <b>Create a new instance for every unit test</b> * </p> * * @author Hannes Dorfmann */ public class HomeViewRobot { private final HomePresenter presenter; private final PublishSubject<Boolean> loadFirstPageSubject = PublishSubject.create(); private final PublishSubject<Boolean> loadNextPageSubject = PublishSubject.create(); private final PublishSubject<Boolean> pullToRefreshSubject = PublishSubject.create(); private final PublishSubject<String> loadAllProductsFromCategorySubject = PublishSubject.create(); private final List<HomeViewState> renderEvents = new CopyOnWriteArrayList<>(); private final ReplaySubject<HomeViewState> renderEventSubject = ReplaySubject.create(); private HomeView view = new HomeView() { @Override public Observable<Boolean> loadFirstPageIntent() { return loadFirstPageSubject; } @Override public Observable<Boolean> loadNextPageIntent() { return loadNextPageSubject; } @Override public Observable<Boolean> pullToRefreshIntent() { return pullToRefreshSubject; } @Override public Observable<String> loadAllProductsFromCategoryIntent() { return loadAllProductsFromCategorySubject; } @Override public void render(HomeViewState viewState) { renderEvents.add(viewState); renderEventSubject.onNext(viewState); } }; public HomeViewRobot(HomePresenter presenter) { this.presenter = presenter; presenter.attachView(view); } public void fireLoadFirstPageIntent() { loadFirstPageSubject.onNext(true); } public void fireLoadNextPageIntent() { loadNextPageSubject.onNext(true); } public void firePullToRefreshIntent() { pullToRefreshSubject.onNext(true); } public void fireLoadAllProductsFromCategory(String category) { loadAllProductsFromCategorySubject.onNext(category); } /** * Blocking waits for view.render() calls and * * @param expectedHomeViewStates The expected HomeViewStates that will be passed to * view.render() */ public void assertViewStateRendered(HomeViewState... expectedHomeViewStates) { if (expectedHomeViewStates == null) { throw new NullPointerException("expectedHomeViewStates == null"); } int eventsCount = expectedHomeViewStates.length; renderEventSubject.take(eventsCount) .timeout(10, TimeUnit.SECONDS) .blockingSubscribe(); /* // Wait for few milli seconds to ensure that no more render events have occurred // before finishing the test and checking expectations (asserts) try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } */ 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); } /** * Simple helper function to print the content of an array as a string */ private String arrayToString(Object[] array) { StringBuffer buffer = new StringBuffer(); for (Object o : array) { buffer.append(o.toString()); buffer.append("\n"); } return buffer.toString(); } }