我有:
val observable: Observable[Int] = Observable.from(List(5))
我可以通过测试测试输入列表确实传递给了observable:
materializeValues(observable) should contain (5)
其中materializeValues
是:
def materializeValues[T](observable: Observable[T]): List[T] = {
observable.toBlocking.toIterable.toList
}
现在,如果我从未来创建一个observable,当测试超时时,我似乎无法使用materializeValues
进行测试。如果我有:
val futVal = Future.successful(5)
val observable: Observable[Int] = Observable.from(futVal)
materializeValues(observable) should contain(5)
它超时并且没有通过测试。在实现这两个可观测量的过程中有什么不同,这导致我无法阻挡它?
另外,测试一个可观察的东西是什么?有没有办法在不调用toBlocking
的情况下这样做?
答案 0 :(得分:1)
我认为问题在于您使用AsyncWordSpecLike
(顺便说一下AsyncWordSpecLike
代替AsyncWordSpec
?)。 AsyncWordSpecLike
/ AsyncWordSpec
旨在简化测试Future
。不幸的是,Observable
是一种更强大的抽象,无法轻松映射到Future
。
特别是AsyncWordSpecLike
/ AsyncWordSpec
允许您的测试返回Future[Assertion]
。为了使它成为可能,它提供了自定义隐式ExecutionContext
,它可以强制执行所有内容并知道所有预定作业何时完成。但是,相同的自定义ExecutionContext
是您的第二个代码不起作用的原因:只有在您的测试代码执行完毕后,您的代码才会在futVal
上阻止,因为计划作业的处理不完整您在Future.onComplete
注册的回调计划在ExecutionContext
上运行。这意味着你有自己的线程死锁。
我不确定在Scala上测试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)
}
}
}