当其中一个参数是回调接口时,模拟另一个函数无法正常工作

时间:2018-04-24 21:58:22

标签: android kotlin mockito

我成功地进行了一些异步函数测试,只有一个回调接口作为mockito-kotlin库的参数,但当我尝试用另一个参数(如String或Integer)测试相同的函数时,我收到错误:

  

org.mockito.exceptions.misusing.InvalidUseOfMatchersException:

     

无效使用参数匹配器!

     

预期2个匹配者,1个记录:

     

- > at com.example.presentation.presenter.MyCollectionPresenterTest.getComicListByHeroOK(MyCollectionPresenterTest.kt:97)

     

如果匹配器与原始值结合使用,则可能发生此异常:

     

//不正确的:

     

someMethod(anyObject(),“raw String”);

     

使用匹配器时,所有参数都必须由匹配器提供。

     

例如:

     

//正确的:

     

someMethod(anyObject(),eq(“by matcher”));

     

有关更多信息,请参阅Matchers类的javadoc。

我确定我正在使用any()正确地模拟回调接口,但我不知道我是否正确地模拟了整数参数。我尝试使用any()anyInt()eq(1)any() as Int但始终存在相同的错误。

以下是我要测试的课程:

@PerFragment
class MyCollectionPresenter @Inject constructor(private val useCase: GetComicListByHeroUseCase) {

    @Inject
    lateinit var view: MyCollectionView
    lateinit var models: List<ComicModel>

    fun getComicListByHero(heroId: Int) {
        useCase.execute(heroId, object : HeroUseCase.GetComicListByHeroCallback {
            override fun onComicListReceived(comicList: List<Comic>) {
                models = ComicModelMapper.toModel(comicList)
                view.setItems(models)
            }

            override fun onError() {
                view.showMessage()
            }

        })
    }
}

这是测试类:

class MyCollectionPresenterTest : UnitTest() {

    private lateinit var presenter: MyCollectionPresenter
    @Mock
    private lateinit var useCase: GetComicListByHeroUseCase
    @Mock
    private lateinit var view: MyCollectionView

    @Before
    fun setUp() {
        presenter = MyCollectionPresenter(useCase)
        initializeView()
    }

    @Test
    fun getComicListByHeroOK() {
        setupGetComicsCallbackOK()

        presenter.getComicListByHero(any())

        verify(presenter.view).setItems(emptyList())
    }

    @Test
    fun getComicListByHeroError() {
        setupGetComicsCallbackError()

        presenter.getComicListByHero(any())

        verify(presenter.view).showMessage()
    }

    private fun initializeView() {
        presenter.view = view
    }

    private fun setupGetComicsCallbackError() {
        doAnswer {
            val callback = it.arguments[0] as HeroUseCase.GetComicListByHeroCallback
            callback.onError()
            null
        }.`when`(useCase).execute(any(), any())
    }

    private fun setupGetComicsCallbackOK() {
        doAnswer {
            val callback = it.arguments[0] as HeroUseCase.GetComicListByHeroCallback
            callback.onComicListReceived(emptyList())
            null
        }.`when`(useCase).execute(any(), any())
    }
}

这是基本单元测试类:

@RunWith(MockitoJUnitRunner::class)
abstract class UnitTest {

    @Suppress("LeakingThis")
    @Rule
    @JvmField
    val injectMocks = InjectMocksRule.create(this@UnitTest)
}

这是一个注入模拟规则的类:

class InjectMocksRule {

    companion object {
        fun create(testClass: Any) = TestRule { statement, _ ->
            MockitoAnnotations.initMocks(testClass)
            statement
        }
    }
}

非常感谢你的帮助,请原谅我的英语。

问候!

更新:我找到了解决方案并发布了答案。

1 个答案:

答案 0 :(得分:0)

最后,我知道我做错了什么。首先,it.argument[1]因为回调是我想要模拟答案的函数的第二个参数。

另一件事是我正在模拟我要测试presenter.getComicListByHero(1)的函数的参数。

以下是修订后的代码:

@Test
fun getComicListByHeroError() {
    setupGetComicsCallbackError()

    presenter.getComicListByHero(1)

    verify(presenter.view).showMessage()
}

private fun setupGetComicsCallbackError() {
    doAnswer {
        val callback = it.arguments[1] as HeroUseCase.GetComicListByHeroCallback
        callback.onError()
        null
    }.`when`(useCase).execute(ArgumentMatchers.anyInt(), any())
}

非常感谢@voghDev的帮助