Тестирование rx-наблюдаемых из Futures/Iterables
Я имею:
val observable: Observable[Int] = Observable.from(List(5))
и я могу проверить, что входной список действительно передается наблюдаемому, проверяя:
materializeValues(observable) should contain (5)
где materializeValues
является:
def materializeValues[T](observable: Observable[T]): List[T] = {
observable.toBlocking.toIterable.toList
}
Теперь, если я создаю наблюдаемое из будущего, я не могу использовать materializeValues
для теста, поскольку тест истекает. Так что если у меня есть:
val futVal = Future.successful(5)
val observable: Observable[Int] = Observable.from(futVal)
materializeValues(observable) should contain(5)
он истекает и не проходит тест. Что отличается в процессе материализации этих двух наблюдаемых, что приводит к тому, что я не могу блокировать это?
Кроме того, каков идиоматический способ проверки наблюдаемого? Есть ли способ сделать это без звонка toBlocking
?
1 ответ
Я думаю, что проблема в том, что вы используете AsyncWordSpecLike
(кстати почему AsyncWordSpecLike
вместо AsyncWordSpec
?). AsyncWordSpecLike
/AsyncWordSpec
предназначены для упрощения тестирования Future
, к несчастью Observable
это более мощная абстракция, которая не может быть легко отображена на Future
,
в частности AsyncWordSpecLike
/AsyncWordSpec
позвольте вашим тестам вернуться Future[Assertion]
, Чтобы сделать это возможным, он предоставляет пользовательские неявные ExecutionContext
что он может заставить все выполнить и знать, когда все запланированные задания завершены. Однако тот же обычай ExecutionContext
причина того, что ваш второй код не работает: обработка запланированных заданий начинается только после завершения выполнения тестового кода, но ваш код блокируется на futVal
потому что, к несчастью для вас, обратный звонок зарегистрирован в Future.onComplete
планируется запустить на ExecutionContext
, Это означает, что у вас есть своего рода тупик с вашим собственным потоком.
Я не уверен, что это официальный способ тестирования Observable
на скале. В Java я думаю, что TestSubscriber является предлагаемым инструментом. Как я сказал Observable
принципиально более мощная вещь, чем Future
так что думаю проверить Observable
вам следует избегать использования AsyncWordSpecLike
/AsyncWordSpec
, Если вы переключитесь на использование FlatSpec
или же WordSpec
Вы можете сделать что-то вроде этого:
class MyObservableTestSpec extends WordSpec with Matchers {
import scala.concurrent.ExecutionContext.Implicits.global
val testValue = 5
"observables" should {
"be testable if created from futures" in {
val futVal = Future.successful(testValue)
val observable = Observable.from(futVal)
val subscriber = TestSubscriber[Int]()
observable(subscriber)
subscriber.awaitTerminalEvent
// now after awaitTerminalEvent you can use various subscriber.assertXyz methods
subscriber.assertNoErrors
subscriber.assertValues(testValue)
// or you can use Matchers as
subscriber.getOnNextEvents should contain(testValue)
}
}
}