【问题标题】:RxJava JUnit test with Retrofit throws a NullPointerException使用 Retrofit 的 RxJava JUnit 测试抛出 NullPointerException
【发布时间】:2017-07-12 01:55:57
【问题描述】:

我有一个 Retrofit2 API 调用

public interface FeedService {
    @GET("/api/v1/feeds")
    Observable<FeedResponse> getFeeds(@Query("page") Integer pageNumber,
                                          @Query("cats") String categories,
                                          @Query("lang") String language);
}

我有一个像这样使用这个 API 的存储库-

public class FeedRepositoryImpl implements FeedRepository {
    private static FeedRepositoryImpl INSTANCE;
    private int FIRST_PAGE = 1;
    private FeedService feedService;

    public static FeedRepositoryImpl getFeedRepository(FeedService feedService) {
        if (INSTANCE == null) {
            INSTANCE = new FeedRepositoryImpl(feedService);
        }
        return INSTANCE;
    }

    @Override
    public Observable<Feed> getFeeds(final int pageNumber, final String categories, final String
            language) {
        return feedService.getFeeds(pageNumber, categories, language)
                .concatMap(new Function<FeedResponse, ObservableSource<? extends Feed>>() {
                    @Override
                    public ObservableSource<? extends Feed> apply(FeedResponse feedResponse) throws
                            Exception {
                        return Observable.fromIterable(feedResponse.feedsData());
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }
}

现在,我正在尝试编写 JUnit 测试来验证 FeedService's getFeeds() 是否使用与调用 FeedRepository.getFeeds() 相同的参数来调用。

但是,我收到了NullPointerException。这是我的测试的样子 -

public class FeedRepositoryImplTest {

    private static String CATEGORIES = "feeds?page=1&cats=top,yt,world,ent,ls,sp";
    private static String LANGUAGE = "lang=en";
    private static int PAGE_NUMBER = 1;

    @Rule
    public ImmediateSchedulersRule immediateSchedulersRule = new ImmediateSchedulersRule();
    @Mock
    FeedService feedService;
    FeedRepositoryImpl feedRepository;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        feedRepository = FeedRepositoryImpl.getFeedRepository(feedService);
    }

    @Test
    public void getFeeds() throws Exception {
        // arrange
        Observable<Feed> emptyFeed = Observable.empty();
        when(feedRepository.getFeed(PAGE_NUMBER, CATEGORIES, LANGUAGE))
                .thenReturn(emptyFeed);

        // act
        feedRepository.getFeed(PAGE_NUMBER, CATEGORIES, LANGUAGE);

        System.out.println("feedRepository.getFeeds(PAGE_NUMBER, CATEGORIES, LANGUAGE)");
        // assert
        verify(feedService).getFeeds(PAGE_NUMBER, CATEGORIES, LANGUAGE);
    }
}

我的TestRule 看起来像这样 -

public class ImmediateSchedulersRule implements TestRule {
    @Override
    public Statement apply(final Statement base, Description description) {
        return () -> {
                RxJavaPlugins.setIoSchedulerHandler((scheduler) -> {
                        return Schedulers.trampoline();
                });
                RxJavaPlugins.setComputationSchedulerHandler((scheduler) -> {
                        return Schedulers.trampoline();
                });
                RxJavaPlugins.setNewThreadSchedulerHandler((scheduler) -> {
                        return Schedulers.trampoline();
                });
                RxAndroidPlugins.setMainThreadSchedulerHandler((scheduler) -> {
                        return Schedulers.trampoline();
                });
                RxAndroidPlugins.setInitMainThreadSchedulerHandler((schedulerCallable) -> {
                        return Schedulers.trampoline();
                });
                base.evaluate();
        };
    }
}

在这一行抛出异常 -

.concatMap(new Function<FeedResponse, ObservableSource<? extends Feed>>() { ... }

我做错了什么?

【问题讨论】:

    标签: android unit-testing junit retrofit2 rx-java2


    【解决方案1】:

    您正在尝试 mock 一个 FoodRepositoryImpl 的方法,它是一个真实的对象(使用模拟的 feedService)。

    改变:

    feedRepository = FeedRepositoryImpl.getFeedRepository(feedService);
    

    feedRepository = Mockito.spy(FeedRepositoryImpl.getFeedRepository(feedService));
    

    编辑:

    您应该将方法模拟更改为(窥探FeedRepositoryImpl 无关紧要):

    when(feedService.getFeeds(PAGE_NUMBER, CATEGORIES, LANGUAGE)).thenReturn(emptyFeed);
    

    【讨论】:

    • 您能详细解释一下吗?我试过了,但在feedService.getFeeds().concatMap() 上仍然有相同的NullPointerException
    • 当然可以。您正在调用when(feedRepository.getFeed(PAGE_NUMBER, CATEGORIES, LANGUAGE)).thenReturn(emptyFeed);,这意味着您正在尝试模拟feedRepository 对象的方法。 Mockito 无法模拟真实对象的方法。 Mockito 能够在完全模拟的对象(使用 @MockMockito.mock)或包装的真实对象(使用 Mockito.spy)上做到这一点。
    • 您嘲笑的唯一对象是feedService。您以正常方式创建了feedRepository(使用模拟的feedService)。
    • 我为feedRepository 删除了when/then 子句本身,并在feedService 上做了一个when/then(正如你所说,这是被嘲笑的东西而不是feedRepository),看起来工作。
    • 好的,我编辑了答案,所以我们在同一页面上。如果在更改之后,您仍然收到NPE,请尝试在创建feedRepository 实例之前设置when/thenReturn
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-26
    • 2014-11-12
    相关资源
    最近更新 更多