У меня возникла проблема с предметами и TestSchedulers. Мои тесты проходят, если я использую планировщик Trampoline, но по какой-то причине они не проходят, если я использую TestScheduler.
Вот мой образец теста и соответствующие классы.
@RunWith(MockitoJUnitRunner::class)
class DemoViewModelTest {
//Error Mocks
private val actionsStream: PublishSubject<DemoContract.ViewEvent> = PublishSubject.create()
private lateinit var viewModel: DemoViewModel
private val handler = mock(DemoContract.Handler::class.java)
@Before
fun setup() {
viewModel = DemoViewModel(schedulersProvider, handler)
viewModel.viewEventsStream = actionsStream
}
@Test
fun testUpdateCounter() {
actionsStream.onNext(DemoContract.ViewEvent.UpdateClick)
testScheduler.triggerActions()
verify(handler).onUpdate()
}
protected var testScheduler = TestScheduler()
protected var schedulersProvider: SchedulersProvider = object : SchedulersProvider() {
override fun mainThread(): Scheduler {
return testScheduler
}
override fun io(): Scheduler {
return testScheduler
}
override fun computation(): Scheduler {
return testScheduler
}
override fun newThread(): Scheduler {
return testScheduler
}
override fun trampoline(): Scheduler {
return testScheduler
}
override fun single(): Scheduler {
return testScheduler
}
}
}
И мой класс ViewModel
class DemoViewModel (val schedulersProvider: SchedulersProvider, val handler:DemoContract.Handler) : DemoContract.ViewModel() {
var viewEventsStream: Observable<DemoContract.ViewEvent>? = null
set(value) {
field = value
subscribeToViewEvents()
}
private fun subscribeToViewEvents() {
viewEventsStream?.let {
it.subscribeOn(schedulersProvider.io())
.observeOn(schedulersProvider.mainThread())
.subscribe(object:Observer<DemoContract.ViewEvent>{
override fun onComplete() {
}
override fun onSubscribe(d: Disposable) {
}
override fun onNext(t: DemoContract.ViewEvent) {
onViewEvent(t)
}
override fun onError(e: Throwable) {
}
})
}
}
fun onViewEvent(event: DemoContract.ViewEvent) {
when (event) {
is DemoContract.ViewEvent.UpdateClick -> {
handler.onUpdate()
}
}
}
}
и мой класс контракта
interface DemoContract {
abstract class ViewModel
sealed class ViewEvent {
object UpdateClick : ViewEvent()
}
interface Handler{
fun onUpdate()
}
}
Несколько слов об этом, если я заменю
viewModel.viewEventsStream = actionsStream
с участием
viewModel.viewEventsStream = Observable.just(DemoContract.ViewEvent.Update)
этот тест проходит.
Может кто-нибудь пролить свет на это, заранее спасибо. Вот минимальный работоспособный проект
Его не вызывают. Вот простой воспроизводимый проект git, если хотите. gitlab.com/anvith/testissues
Перед вызовом actionsStream.hasObservers проверьте, верно ли значение onNext.
subscribeToViewEvents когда-нибудь вызывается?
@akarnokd Для actionsStream.hasObservers установлено значение false, событие subscribeToViewEvents вызывается в результате viewModel.viewEventsStream = actionsStream. Я проверил, что метод onSubscribe вызывается с объектом подписки. Также извиняюсь за кросс-пост.
actionsStream.hasObservers - false <- проблема в том, что вы не оформляете подписку вовремя, поэтому некому получить товар.
Спасибо, что указали мне правильное направление :)
Большое спасибо @akarnokd за то, что указал мне в правильном направлении. Оказывается, это состояние гонки между подписчиком добавляемого PublishSubject (вызов subscribeActual) и вызовом onNext, который у меня был триггер в моем тесте. Вызов onNext возвращается до того, как произойдет первое.
Решение состоит в том, чтобы явно вызвать triggerActions дважды, один раз сразу после подписки и один раз после выпуска.
Измените это
@Before
fun setup() {
viewModel = DemoViewModel(schedulersProvider, handler)
viewModel.viewEventsStream = actionsStream
}
К
@Before
fun setup() {
viewModel = DemoViewModel(schedulersProvider, handler)
viewModel.viewEventsStream = actionsStream
testScheduler.triggerActions()
}
Что произойдет, если вы вставите оператор регистрации перед оператором
subscribeOn()? Попробуйте.doOnNext( v -> logger.debug(v.toString())-