在Android中的MVP演示者中对RxJava进行单元测试

时间:2018-04-10 01:05:50

标签: unit-testing tdd rx-java integration-testing rx-java2

我是TDD的新手。也是MVP和Rxjava的新手。我只是潜入它,这是值得的。但我坚持在测试部分。我理解单元测试的基础。这对我来说有点困难。但我坚持到这里,那么如何测试主持人呢?

这是Presenter类 -

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();
}

}

这是视图界面 -

public interface MainView {

void showWait();

void removeWait();

void onFailure(String appErrorMessage);

void getNewsListSuccess(Articles articles);

}

这是RxJavaService类 -

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");
                }
            });
}

}

这是我被困的测试课 -

@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 个答案:

答案 0 :(得分:0)

首先是

  1. 如果你进入TDD,你永远不会陷入你描述的情况。在TDD中,您启动,测试失败,然后再编写实现。所以你的问题更多的是测试TDD。
  2. 我建议切换到RxJava2,因为RxJava1将于3月31日到达End of Life。
  3. 我很奇怪RxJavaService将API从发布/订阅更改为回调。为什么不坚持使用rx API一直到演示者?
  4. 使用模拟的RxJavaService进行测试

    如果您希望使用测试中的设置完成测试,则看起来像这样:

    @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);
    }
    

    你可以通过不使用Mockito模拟RxJavaService来摆脱丑陋的代码,而是滚动你自己的手写模拟,它会存储回调并将其提供给测试。

    但是,我建议采用不同的方法。

    使用真实的RxJavaService进行测试并模拟NewsRestService

    如果我们只嘲笑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));
        }
    
    }