在单元测试中多次调用该方法,但在代码中未多次调用该方法

时间:2018-12-28 20:32:20

标签: android unit-testing kotlin mockito rx-java2

我正在向使用RxJava 2的类编写单元测试。当在观察者上调用onNext()时,我希望printV()被调用一次。在代码中,一次调用成功。但是,当我在单元测试中测试此片段时,该方法被调用3次。

问题在于如何使它在测试中仅被调用一次,以及为什么在测试中它被调用比实际代码中多次。

onMenuLoaded()

从日志中可以看到该方法的调用位置

//in ViewModel class, under testing
fun loadMenu() {       
        menuInteractorImpl.getMainMenu()?.subscribeOn(Schedulers.io())?.observeOn(AndroidSchedulers.mainThread())?.subscribe(
                { items ->
                    onMenuLoaded(items)
                },
                { error ->
                    //error handling logic
                }
                )?.let { compositeDisposables.add(it) }
}
    //Test
@RunWith(PowerMockRunner::class)
@PowerMockRunnerDelegate(MockitoJUnitRunner::class)
@PrepareForTest(MenuInteractorImpl::class, MainMenuViewModel::class)
class MainMenuViewModelTest {

    @get:Rule
    var instantExecutorRule = InstantTaskExecutorRule()

    companion object {
        @ClassRule
        @JvmField
        val schedulers = RxImmediateSchedulerRule()
    }

    @Before
    fun setUp() {
        doNothing().`when`(viewModel).startTimerToScrollViewPager()
    }

    @Test
    fun `test load menu calls onMenuLoaded when success`() {            
            val mockObservable = Observable.just(mockDataFactory.mockMenu).doOnNext {

            viewModel.onMenuLoaded(it)
        }.subscribeOn(Schedulers.newThread())
        Mockito.`when`(menuInteractorImpl.getMainMenu()).thenReturn(mockObservable)

        viewModel.loadMenu() //this method is called 3 times
        Mockito.verify(viewModel, times(1)).onMenuLoaded(any())
    }

解决方案: 问题在于意外地将PowerMockito viewModel.loadMenu(); -> at com.example.mainmenu.MainMenuViewModelTest.test load menu calls onMenuLoaded when success(MainMenuViewModelTest.kt:88) viewModel.loadMenu(); -> at org.powermock.core.MockGateway.doMethodCall(MockGateway.java:182) viewModel.loadMenu(); -> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 和Mockito spy组合在一起。导入Mockito的mock时,问题已解决。

2 个答案:

答案 0 :(得分:0)

您的真实代码正在onMenuLoaded(items)中调用onNext,然后您的模拟可观察对象还从doOnNext对其进行调用。

您需要删除可观察到的模拟中的doOnNext部分:

@Test
fun `test load menu calls onMenuLoaded when success`() {            
    val mockObservable = Observable.just(mockDataFactory.mockMenu)
                                .subscribeOn(Schedulers.newThread())
    Mockito.`when`(menuInteractorImpl.getMainMenu()).thenReturn(mockObservable)

    viewModel.loadMenu() //this method is called 3 times
    Mockito.verify(viewModel, times(1)).onMenuLoaded(any())
}

答案 1 :(得分:0)

问题出在意外地将PowerMockito间谍和Mockito模拟结合在一起。导入Mockito的间谍时,此问题已解决。

编辑: 我再次遇到相同的问题,解决方案则不同。看起来是将PowerMockito和Mockito组合在一起是同样的原因。这次我通过添加一个doNothing

解决了这个问题
    doNothing().`when`(viewModel).myCall(true)