运行 视图模型测试使用 liveData 和 rxJava Single 时出现空指针异常
Null pointer exception when running viewmodel test using liveData and rxJava Single
我想用单元测试覆盖 ViewModel。但是当 运行 它们时得到 NullPointerException。
ViewModel实现如下:
- 交互器和调度器通过构造函数注入
- 订阅 RxJava Single
- 和 post 值在 liveData
// 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
- 设置规则
- 模拟交互者
- 为 liveDatas 设置观察者
- 做出断言
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();
。
我想用单元测试覆盖 ViewModel。但是当 运行 它们时得到 NullPointerException。
ViewModel实现如下:
- 交互器和调度器通过构造函数注入
- 订阅 RxJava Single
- 和 post 值在 liveData
// 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
- 设置规则
- 模拟交互者
- 为 liveDatas 设置观察者
- 做出断言
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();
。