运行 视图模型测试使用 liveData 和 rxJava Single 时出现空指针异常

Null pointer exception when running viewmodel test using liveData and rxJava Single

我想用单元测试覆盖 ViewModel。但是当 运行 它们时得到 NullPointerException。

ViewModel实现如下:

// constructor 
 public ProductListViewModel(
        GetCellphonesInteractor getCellphonesInteractor,
        GetCellphonesByNameInteractor getCellphonesByNameInteractor,
        GetFilteredCellphonesInteractor getFilteredCellphonesInteractor,
        BaseSchedulerProvider schedulerProvider
    ) {
        this.getCellphonesInteractor = getCellphonesInteractor;
        this.getCellphonesByNameInteractor = getCellphonesByNameInteractor;
        this.getFilteredCellphonesInteractor = getFilteredCellphonesInteractor;
        this.schedulerProvider = schedulerProvider;
        getCellphones();
    }

// method 
void getCellphones() {
        getCellphonesInteractor
            .getCellPhones()
            .subscribeOn(schedulerProvider.io())
            .observeOn(schedulerProvider.io())
            .subscribe(new SingleObserver<Cellphone[]>() {
                @Override
                public void onSubscribe(@NonNull Disposable d) {
                    disposables.add(d);
                    _isRefreshing.postValue(true);
                }

                @Override
                public void onSuccess(@NonNull Cellphone[] cellphones) {
                    _cellphonesLiveData.postValue(cellphones);
                    _isRefreshing.postValue(false);
                }

                @Override
                public void onError(@NonNull Throwable e) {
                    _isRefreshing.postValue(false);
                }
            });
    }

测试中class

public class ProductListViewModelTest {
    @Rule
    public InstantTaskExecutorRule instantTaskExecutorRule = new InstantTaskExecutorRule();

    @Rule
    public RxSchedulerRule rxSchedulerRule = new RxSchedulerRule();

    @Rule
    public MockitoRule rule = MockitoJUnit.rule();

    @Mock
    GetCellphonesInteractor getCellphonesInteractor;
    @Mock
    GetCellphonesByNameInteractor getCellphonesByNameInteractor;
    @Mock
    GetFilteredCellphonesInteractor getFilteredCellphonesInteractor;

    @Mock
    Observer<Cellphone[]> cellphones;
    @Mock
    Observer<Boolean> isRefreshing;

    TrampolineSchedulerProvider trampolineSchedulerProvider = new TrampolineSchedulerProvider();

    private ProductListViewModel productListViewModel;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        productListViewModel = new ProductListViewModel(
            getCellphonesInteractor,
            getCellphonesByNameInteractor,
            getFilteredCellphonesInteractor,
            trampolineSchedulerProvider
        );
    }

    @Test
    public void testGetCellphones_whenReturnsData() {
        Cellphone[] dummyCellphones = DummyCellphoneFactory.generateCellphones();
      Mockito.when(getCellphonesInteractor.getCellPhones()).thenReturn(Single.just(dummyCellphones));

        productListViewModel.isRefreshing.observeForever(isRefreshing);
        productListViewModel.cellphonesLiveData.observeForever(cellphones);

        productListViewModel.getCellphones();

        Mockito.verify(isRefreshing).onChanged(true);
        Mockito.verify(cellphones).onChanged(dummyCellphones);
        Mockito.verify(isRefreshing).onChanged(false);
    }
}

这里是stacktrace,指向viewModel的getCellphones方法中的subscribeOn

java.lang.NullPointerException
    at com.online.shop.ui.list.ProductListViewModel.getCellphones(ProductListViewModel.java:61)
    at com.online.shop.ui.list.ProductListViewModel.<init>(ProductListViewModel.java:51)
    at com.online.shop.ui.list.ProductListViewModelTest.setUp(ProductListViewModelTest.java:53)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:59)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
    at org.junit.internal.runners.statements.RunBefores.invokeMethod(RunBefores.java:33)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.mockito.internal.junit.JUnitSessionStore.evaluateSafely(JUnitSessionStore.java:55)
    at org.mockito.internal.junit.JUnitSessionStore.evaluate(JUnitSessionStore.java:43)
    at org.junit.rules.TestWatcher.evaluate(TestWatcher.java:61)
    at com.online.shop.ui.utils.RxSchedulerRule.evaluate(RxSchedulerRule.java:25)
    at com.online.shop.ui.utils.RxImmediateSchedulerRule.evaluate(RxImmediateSchedulerRule.java:46)
    at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:306)
    at org.junit.runners.BlockJUnit4ClassRunner.evaluate(BlockJUnit4ClassRunner.java:100)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:331)
    at org.junit.runners.ParentRunner.schedule(ParentRunner.java:79)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    at org.junit.runners.ParentRunner.access0(ParentRunner.java:66)
    at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:293)
    at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:306)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
    at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
    at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:121)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
    at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    at org.gradle.internal.concurrent.ManagedExecutorImpl.run(ManagedExecutorImpl.java:48)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
    at java.base/java.lang.Thread.run(Thread.java:829)

根据堆栈跟踪和 ProductListViewModel 的参数,我假设您在存储它使用的引用 this.getCellphonesInteractor = getCellphonesInteractor; 之前调用了 getCellphones();