Я пытаюсь протестировать метод внутри ViewModel, который опирается на случай использования Rx Android. Проблема связана с архитектурой, которую я использую, я могу напрямую протестировать сценарий использования, но у меня возникают проблемы с методом из ViewModel, так как мне нужно иметь возможность настроить ответ asyn c, а затем убедитесь, что некоторые взаимодействия с шиной событий происходят после завершения операции.
Вот мой базовый класс варианта использования:
abstract class BaseUseCase {
@Inject
lateinit var scheduler: IScheduler
private var subscription: Disposable? = Disposables.empty()
fun <T : Any> execute(
single: Single<T>,
onSuccess: Consumer<T>,
onError: Consumer<in Throwable>
) {
subscription = single
.compose(scheduler.applySingleDefaultSchedulers())
.subscribe(onSuccess, onError)
}
fun execute(
completable: Completable,
onSuccess: Action,
onError: Consumer<Throwable>
) {
completable.let {
subscription = completable
.compose(scheduler.applyCompletableDefaultSchedulers())
.subscribe(onSuccess, onError)
}
}
}
Мой модифицированный Api: interface ItemsApi {
@POST("/endpoint/items/search/")
@ErrorType(BaseResponse::class)
fun searchItems(@Body request: ItemsSearchRequest):
Single<BaseResponse<ItemsSearchResponse>>
}
Вот пример использования, который использует ViewModel:
class ItemsUseCase @Inject constructor(private val itemsApi: ItemsApi) : BaseUseCase() {
fun searchItems(request: ItemSearchRequest) =
itemsApi.searchItems(request)
}
Теперь метод внутри viewModel, который я хочу проверить:
class ItemsListViewModel @Inject constructor(
private var itemsUseCase: ItemsUseCase,
private val bus: Bus
) {
fun searchItems(filter: String) {
itemsUseCase.execute(
itemsUseCase.searchItems(ItemsSearchRequest(filter)),
Consumer { response ->
bus.post(ItemsSuccessEvent(response.content.items))
},
Consumer { error ->
bus.post(ItemsErrorEvent(error))
}
)
}
}
Наконец, тест я не в состоянии закончить sh:
@RunWith(MockitoJUnitRunner::class)
class NotificationsListViewModelTest {
@Mock
lateinit var itemsUseCaseMock: ItemsUseCase
@Mock
lateinit var busMock: Bus
// System under test
private lateinit var sut: ItemsListViewModel
@Rule
@JvmField
var rule: TestRule = InstantTaskExecutorRule()
@Before
fun setUp() {
sut = ItemsListViewModel(itemsUseCaseMock, busMock)
}
@Test
fun searchItemsSuccess() {
val filter = "filter"
val itemsList = mutableListOf<Item>().apply {
add(Item("default"))
}
val request = ItemsSearchRequest(filter)
val response = BaseResponse(ItemsSearchResponse(itemsList))
// Setup async response
doAnswer {
// In Java I usully do the following:
// Get the callback from the invocation arguments (in this case "it.arguments[0]" for example)
// Call "onSuccess" or "onFailure" from the callback with the desired response
}.whenever(itemsUseCaseMock).searchItems(request)
// Execute the method I'm testing
sut.searchItems(searchCriteria)
// Verify that the event was posted with the proper data
argumentCaptor<ItemsSuccessEvent>().apply {
verify(bus).publish(capture())
assertEquals(itemsList, allValues[0].items)
}
}
}
Есть идеи? Заранее спасибо!