如何测试return Future 的方法?
How to test methods that return Future?
我想测试一个 returns 和 Future
的方法。我的尝试如下:
import org.specs2.mutable.Specification
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}
class AsyncWebClientSpec extends Specification{
"WebClient when downloading images" should {
"for a valid link return non-zero content " in {
val testImage = AsyncWebClient.get("https://www.google.cz/images/srpr/logo11ww.png")
testImage.onComplete { res =>
res match {
case Success(image) => image must not have length(0)
case _ =>
}
AsyncWebClient.shutDown
}
}
}
}
除了我无法使这段代码工作之外,我想可能有更好的方法来使用面向 Future
的匹配器来测试期货。
如何在specs2中正确地做到这一点?
onComplete
returns Unit
,所以代码块 returns 立即结束,测试在能够做任何事情之前结束。为了正确测试 Future
的结果,您需要阻塞直到它完成。您可以使用 Await
并设置最大等待时间 Duration
。
import scala.concurrent._
import scala.concurrent.duration._
Await.result(testImage, Duration("10 seconds")) must not have length(0)
您可以使用 Matcher.await
方法将 Matcher[T]
转换为 Matcher[Future[T]]
:
val testImage: Future[String] =
AsyncWebClient.get("https://www.google.cz/images/srpr/logo11ww.png")
// you must specify size[String] here to help type inference
testImage must not have size[String](0).await
// you can also specify a number of retries and duration between retries
testImage must not have size[String](0).await(retries = 2, timeout = 2.seconds)
// you might also want to check exceptions in case of a failure
testImage must throwAn[Exception].await
在 specs2 中有一件好事 - Future[Result]
的隐式 await
方法。如果你利用未来的转换,你可以这样写:
"save notification" in {
notificationDao.saveNotification(notification) map { writeResult =>
writeResult.ok must be equalTo (true)
} await
}
当需要使用异步函数进行一些数据排列时,未来的组合会派上用场:
"get user notifications" in {
{
for {
_ <- notificationDao.saveNotifications(user1Notifications)
_ <- notificationDao.saveNotifications(user2Notifications)
foundUser1Notifications <- notificationDao.getNotifications(user1)
} yield {
foundUser1Notifications must be equalTo (user1Notifications)
}
} await
}
请注意,我们必须如何使用额外的块来理解 for-comprehension 来说服编译器。我认为它很吵,所以如果我们在函数中使用 await
方法,我们会想出一个更好的语法:
def awaiting[T]: Future[MatchResult[T]] => Result = { _.await }
"get user notifications" in awaiting {
for {
_ <- notificationDao.saveNotifications(user1Notifications)
_ <- notificationDao.saveNotifications(user2Notifications)
foundUser1Notifications <- notificationDao.getNotifications(user1)
} yield {
foundUser1Notifications must be equalTo (user1Notifications)
}
}
想知道为什么@etorreborre 没有提到 "eventually"
class EventuallyMatchersSpec extends Specification with FutureMatchers with ExpectationsDescription { section("travis")
addParagraph { """
`eventually` can be used to retry any matcher until a maximum number of times is reached
or until it succeeds.
""" }
"A matcher can match right away with eventually" in {
1 must eventually(be_==(1))
}
"A matcher can match right away with eventually, even if negated" in {
"1" must not (beNull.eventually)
}
"A matcher will be retried automatically until it matches" in {
val iterator = List(1, 2, 3).iterator
iterator.next must be_==(3).eventually
}
"A matcher can work with eventually and be_== but a type annotation is necessary or a be_=== matcher" in {
val option: Option[Int] = Some(3)
option must be_==(Some(3)).eventually
}
我花了一段时间才找到这个所以我想分享一下。我应该阅读发行说明。在 specs2 v3.5 中,需要使用隐式 ExecutionEnv 才能使用 await for future。这也可以用于未来的转换(即地图)见http://notes.implicit.ly/post/116619383574/specs2-3-5。
从那里摘录以供快速参考:
import org.specs2.concurrent.ExecutionEnv
class MySpec extends mutable.Specification {
"test of a Scala Future" >> { implicit ee: ExecutionEnv =>
Future(1) must be_>(0).await
}
}
等待是一种反模式。永远不应该使用它。
您可以使用 ScalaFutures
、IntegrationPatience
和 Eventually
.
等特征
whenReady
提供您正在寻找的魔法。
示例:
import org.specs2.mutable.Specification
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}
import org.scalatest.concurrent.{IntegrationPatience, ScalaFutures}
import scala.concurrent.Future
class AsyncWebClientSpec extends Specification
with ScalaFutures
with IntegrationPatience {
"WebClient when downloading images" should {
"for a valid link return non-zero content " in {
whenReady(Future.successful("Done")){ testImage =>
testImage must be equalTo "Done"
// Do whatever you need
}
}
}
}
我想测试一个 returns 和 Future
的方法。我的尝试如下:
import org.specs2.mutable.Specification
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}
class AsyncWebClientSpec extends Specification{
"WebClient when downloading images" should {
"for a valid link return non-zero content " in {
val testImage = AsyncWebClient.get("https://www.google.cz/images/srpr/logo11ww.png")
testImage.onComplete { res =>
res match {
case Success(image) => image must not have length(0)
case _ =>
}
AsyncWebClient.shutDown
}
}
}
}
除了我无法使这段代码工作之外,我想可能有更好的方法来使用面向 Future
的匹配器来测试期货。
如何在specs2中正确地做到这一点?
onComplete
returns Unit
,所以代码块 returns 立即结束,测试在能够做任何事情之前结束。为了正确测试 Future
的结果,您需要阻塞直到它完成。您可以使用 Await
并设置最大等待时间 Duration
。
import scala.concurrent._
import scala.concurrent.duration._
Await.result(testImage, Duration("10 seconds")) must not have length(0)
您可以使用 Matcher.await
方法将 Matcher[T]
转换为 Matcher[Future[T]]
:
val testImage: Future[String] =
AsyncWebClient.get("https://www.google.cz/images/srpr/logo11ww.png")
// you must specify size[String] here to help type inference
testImage must not have size[String](0).await
// you can also specify a number of retries and duration between retries
testImage must not have size[String](0).await(retries = 2, timeout = 2.seconds)
// you might also want to check exceptions in case of a failure
testImage must throwAn[Exception].await
在 specs2 中有一件好事 - Future[Result]
的隐式 await
方法。如果你利用未来的转换,你可以这样写:
"save notification" in {
notificationDao.saveNotification(notification) map { writeResult =>
writeResult.ok must be equalTo (true)
} await
}
当需要使用异步函数进行一些数据排列时,未来的组合会派上用场:
"get user notifications" in {
{
for {
_ <- notificationDao.saveNotifications(user1Notifications)
_ <- notificationDao.saveNotifications(user2Notifications)
foundUser1Notifications <- notificationDao.getNotifications(user1)
} yield {
foundUser1Notifications must be equalTo (user1Notifications)
}
} await
}
请注意,我们必须如何使用额外的块来理解 for-comprehension 来说服编译器。我认为它很吵,所以如果我们在函数中使用 await
方法,我们会想出一个更好的语法:
def awaiting[T]: Future[MatchResult[T]] => Result = { _.await }
"get user notifications" in awaiting {
for {
_ <- notificationDao.saveNotifications(user1Notifications)
_ <- notificationDao.saveNotifications(user2Notifications)
foundUser1Notifications <- notificationDao.getNotifications(user1)
} yield {
foundUser1Notifications must be equalTo (user1Notifications)
}
}
想知道为什么@etorreborre 没有提到 "eventually"
class EventuallyMatchersSpec extends Specification with FutureMatchers with ExpectationsDescription { section("travis")
addParagraph { """
`eventually` can be used to retry any matcher until a maximum number of times is reached
or until it succeeds.
""" }
"A matcher can match right away with eventually" in {
1 must eventually(be_==(1))
}
"A matcher can match right away with eventually, even if negated" in {
"1" must not (beNull.eventually)
}
"A matcher will be retried automatically until it matches" in {
val iterator = List(1, 2, 3).iterator
iterator.next must be_==(3).eventually
}
"A matcher can work with eventually and be_== but a type annotation is necessary or a be_=== matcher" in {
val option: Option[Int] = Some(3)
option must be_==(Some(3)).eventually
}
我花了一段时间才找到这个所以我想分享一下。我应该阅读发行说明。在 specs2 v3.5 中,需要使用隐式 ExecutionEnv 才能使用 await for future。这也可以用于未来的转换(即地图)见http://notes.implicit.ly/post/116619383574/specs2-3-5。
从那里摘录以供快速参考:
import org.specs2.concurrent.ExecutionEnv
class MySpec extends mutable.Specification {
"test of a Scala Future" >> { implicit ee: ExecutionEnv =>
Future(1) must be_>(0).await
}
}
等待是一种反模式。永远不应该使用它。
您可以使用 ScalaFutures
、IntegrationPatience
和 Eventually
.
whenReady
提供您正在寻找的魔法。
示例:
import org.specs2.mutable.Specification
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}
import org.scalatest.concurrent.{IntegrationPatience, ScalaFutures}
import scala.concurrent.Future
class AsyncWebClientSpec extends Specification
with ScalaFutures
with IntegrationPatience {
"WebClient when downloading images" should {
"for a valid link return non-zero content " in {
whenReady(Future.successful("Done")){ testImage =>
testImage must be equalTo "Done"
// Do whatever you need
}
}
}
}