Unit testing RxJava in MVP presenter in android

落爺英雄遲暮 提交于 2020-01-06 07:15:15

问题


I am new to TDD. Also new to MVP and Rxjava. I just dive into it and It is worth it. But I stuck at the testing part. I understand the basis of unit testing. It is a little bit difficult for me in beginning. But I stuck here and So how can test the presenter?

Here is the Presenter class -

public class NewsPresenter {

private final RxjavaService service;
private final MainView view;
private CompositeSubscription subscriptions;

public NewsPresenter(RxjavaService service, MainView view) {
    this.service = service;
    this.view = view;
    subscriptions = new CompositeSubscription();
}

public void getNewsList(String urlQ){
    view.showWait();

    Subscription subscription = service.getNews(urlQ ,new RxjavaService.GetNewsCallback() {
        @Override
        public void onSuccess(Articles articles) {
            view.removeWait();
            view.getNewsListSuccess(articles);
        }

        @Override
        public void onError(NetworkError networkError) {
            view.removeWait();
            view.onFailure(networkError.getAppErrorMessage());
            Log.i("huh",networkError.getMessage());
        }
    });

    subscriptions.add(subscription);
}

public void onStop(){
    subscriptions.unsubscribe();
}

}

Here is the View Interface -

public interface MainView {

void showWait();

void removeWait();

void onFailure(String appErrorMessage);

void getNewsListSuccess(Articles articles);

}

Here is the RxJavaService class -

public class RxjavaService {

private final NewsRestService newsRestService;

public RxjavaService(NewsRestService newsRestService) {
    this.newsRestService = newsRestService;
}


public interface GetNewsCallback {
    void onSuccess(Articles articles);

    void onError(NetworkError networkError);
}


public Subscription getNews(String q, final GetNewsCallback getNewsCallback) {
    Log.i("stuck","service called");
    return newsRestService.getNewsBySearch(q,"8dca7dea475e41e49518b2c61131e118",100)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .onErrorResumeNext(new Func1<Throwable, Observable<? extends Articles>>() {
                @Override
                public Observable<? extends Articles> call(Throwable throwable) {
                    return Observable.error(throwable);
                }
            })
            .subscribe(new Subscriber<Articles>() {
                @Override
                public void onCompleted() {
                    Log.i("stuck","complete");
                }

                @Override
                public void onError(Throwable e) {
                    getNewsCallback.onError(new NetworkError(e));
                    Log.i("stuck",e.getMessage());
                }

                @Override
                public void onNext(Articles articles) {
                    getNewsCallback.onSuccess(articles);
                    Log.i("stuck","Onnext");
                }
            });
}

}

Here is the Test class where I am stuck-

@RunWith(MockitoJUnitRunner.class)

public class NewsListTest {

private NewsPresenter newsPresenter;

@Mock
private RxjavaService rxjavaService;
@Mock
private MainView mainView;

@Before
public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);

    newsPresenter = new NewsPresenter(rxjavaService,mainView);
}

@After
public void tearDown() throws Exception {
    mainView = null;
    newsPresenter.onStop();
}

@Test
public void Testing_The_Result() {

}

}


回答1:


First things first

  1. If you're into TDD, you'd never get into the situation you described. In TDD you start with a failing test, and just then go write the implementation. So your question is much more about testing then TDD.
  2. I would recommend switching to RxJava2, as RxJava1 reaches End Of Life on March 31.
  3. Look strange to me that RxJavaService changes the API from publish/subscribe to callbacks. Why not stick with rx API all the way to presenter?

Test with mocked RxJavaService

If you'd like to finish writing the test with the setup you have in the test, it would look something like this:

@Test
public void Testing_The_Result() {
    final RxjavaService.GetNewsCallback[] callback = new RxjavaService.GetNewsCallback[1];
    Mockito.when(rxjavaService.getNews(ArgumentMatchers.anyString(), ArgumentMatchers.any(RxjavaService.GetNewsCallback.class))).thenAnswer(new Answer<Subscription>() {
        public Subscription answer(InvocationOnMock invocationOnMock) {
            callback[0] = invocationOnMock.getArgument(1);
            return mock(Subscription.class);
        }
    });
    newsPresenter.getNewsList("some url");
    Articles articles = new Articles();

    callback[0].onSuccess(articles);

    verify(mainView).removeWait();
    verify(mainView).getNewsListSuccess(articles);
}

You can get rid of the ugly code by not using Mockito to mock RxJavaService, but rather roll you own hand-written mock, which would store the callback and provide it to the test.

However, I'd recommend a different approach.

Test with real RxJavaService and mocked NewsRestService

I'd say it makes more sense and gives a better test if we mocked only the NewsRestService:

@RunWith(MockitoJUnitRunner.class)
public class NewsList2Test {

    private NewsPresenter newsPresenter;

    @Mock
    private MainView mainView;
    @Mock
    private NewsRestService newsRestService;

    @Before
    public void setUp() {
        newsPresenter = new NewsPresenter(new RxjavaService(newsRestService), mainView);
    }

    @Test
    public void show_success_in_view_when_there_are_articles() {
        when(newsRestService.getNewsBySearch(eq("some url"), anyString(), anyInt()))
                .thenReturn(Observable.just(new Articles()));

        newsPresenter.getNewsList("some url");

        verify(mainView).removeWait();
        verify(mainView).getNewsListSuccess(any(Articles.class));
    }

}


来源:https://stackoverflow.com/questions/49743749/unit-testing-rxjava-in-mvp-presenter-in-android

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!