ArgumentCaptor vs InOrder для проверки последующих обратных вызовов с разными аргументами

Я тестировал свой класс DAO, сгенерированный с использованием библиотеки Room из Architecture Components . Я хотел проверить, будет ли LiveData возвращаемая запросом, соединяющим несколько таблиц, при изменении данных.

Я начал с проверки InOrder , но обнаружил, что любой аргумент, который я хотел бы утверждать, Mockito сказал бы, что метод был вызван с другим (и когда я изменил это утверждение на это, он сказал бы, что это был другой) ,

Использование ArgumentCaptor оказалось подходящим для этой цели, что является предметом этого вопроса:

Почему здесь работает проверка ArgumentCaptor , но InOrder этого не делает?

Рассматривая ответы на вопрос о том, как проверять несколько вызовов методов с разными параметрами , оба метода должны работать нормально.

Вот упрощенная версия моего теста, которая демонстрирует проблему:

 package com.example import com.nhaarman.mockito_kotlin.argumentCaptor import com.nhaarman.mockito_kotlin.check import com.nhaarman.mockito_kotlin.mock import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.* import org.mockito.junit.MockitoJUnitRunner @Suppress("IllegalIdentifier") @RunWith(MockitoJUnitRunner::class) class MultipleCallbacksVanillaTest { private val java = Language("Java") private val javascript = Language("JavaScript") private val kotlin = Language("Kotlin") private val firstList = emptyList<Language>() private val secondList = listOf(java) private val thirdList = listOf(java, javascript, kotlin) private val lastList = listOf(java, kotlin) @Test fun `using argument captor`() { // given val observer = mock<Observer<List<Language>>>() val liveData = MutableLiveData<List<Language>>() // when liveData.observeForever(observer) liveData.value = firstList liveData.value = secondList liveData.value = thirdList liveData.value = lastList // then argumentCaptor<List<Language>>().run { verify(observer, times(4)).onChanged(capture()) val (firstValue, secondValue, thirdValue, lastValue) = allValues assertEquals(firstList, firstValue) assertEquals(secondList, secondValue) assertEquals(thirdList, thirdValue) assertEquals(lastList, lastValue) } } @Test fun `using in order`() { // given val observer = mock<Observer<List<Language>>>() val liveData = MutableLiveData<List<Language>>() // when liveData.observeForever(observer) liveData.value = firstList liveData.value = secondList liveData.value = thirdList liveData.value = lastList // then inOrder(observer).run { verify(observer).onChanged(check { assertEquals(firstList, it) }) verify(observer).onChanged(check { assertEquals(secondList, it) }) verify(observer).onChanged(check { assertEquals(thirdList, it) }) verify(observer).onChanged(check { assertEquals(lastList, it) }) } verifyNoMoreInteractions(observer) } } data class Language(val name: String) interface Observer<in T> { fun onChanged(value: T?) } class MutableLiveData<T : Any> { var value: T get() = _value set(value) { observers.forEach { it.onChanged(value) } _value = value } private lateinit var _value: T private var observers = mutableSetOf<Observer<T>>() fun observeForever(observer: Observer<T>) { if (::_value.isInitialized) observer.onChanged(_value) observers.add(observer) } } 

using argument captor , но using in order не выполняется с сообщением:

 java.lang.AssertionError: Expected :[] Actual :[Language(name=Java)] 

TL; DR – это, по-видимому, ошибка и / или плохая документация по части Mockito-Kotlin с точки зрения ее функции check .

Вики Mockito-Kotlin говорит :

Если вы хотите сделать больше утверждений о полученном аргументе, вы можете использовать check . […] Если вы хотите, чтобы ваш тест вышел из строя внутри вызова check , вы должны убедиться, что тело выдает ошибку […]

Выполнение check вызывает аргумент Mockito argThat и передает предоставленный предикат в качестве аргумента. Однако в документации для ArgumentMatcher указано :

Метод не должен утверждать, если аргумент не соответствует. Он должен возвращать только false .

Таким образом, документация Mockito-Kotlin находится в прямом противоречии с этим ограничением.

Я не уверен, как это исправить, но вы можете просто полностью исключить check и использовать argThat напрямую (вернув false если argThat , а не бросать).

Использование check (вместо той, что предоставляется Mockito-Kotlin), функционирует подобно этому, кажется, работает нормально:

 inline fun <reified T> check(noinline predicate: (T?) -> Unit): T? { return Mockito.argThat { try { predicate(it) true } catch (e: Throwable) { false } } }