I want to cover ViewModel with unit tests. But getting NullPointerException when running them.
ViewModel implementation is as follows:
- interactors and Schedulers are injected through the constructor
- subscribe on RxJava Single
- and post values in 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 one rror(@NonNull Throwable e) {
_isRefreshing.postValue(false);
}
});
}
In test class
- Set rules
- Mocked interactors
- Set observers for liveDatas
- Make assertions
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);
}
}
Here is stacktrace, which points to subscribeOn in getCellphones method of viewModel
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$1.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$1.evaluateSafely(JUnitSessionStore.java:55)
at org.mockito.internal.junit.JUnitSessionStore$1.evaluate(JUnitSessionStore.java:43)
at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:61)
at com.online.shop.ui.utils.RxSchedulerRule$1.evaluate(RxSchedulerRule.java:25)
at com.online.shop.ui.utils.RxImmediateSchedulerRule$2.evaluate(RxImmediateSchedulerRule.java:46)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.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$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.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$1.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)
CodePudding user response:
Based on the stacktrace and the arguments of ProductListViewModel
, I presume you called the getCellphones();
before storing the reference this.getCellphonesInteractor = getCellphonesInteractor;
it uses.