如何测试返回Future的方法?

jak*_*sky 16 scala specs2

我想测试一个返回a的方法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
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

除了我无法使这个代码工作的事实,我想有一个更好的方法来测试一个Future定向匹配器的期货.

如何在specs2中正确完成?

Eri*_*ric 20

您可以使用该Matcher.await方法将a 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
Run Code Online (Sandbox Code Playgroud)

  • 我需要任何特殊的进口才能使它有效吗?我正在使用specs2 3.6.2,我收到以下错误:`值await不是org.specs2.matcher.BeEqualTo`的成员.[错误] Future(1)必须是EquaTo(1).await` (5认同)
  • 是的,你需要一个隐含的[执行环境](https://etorreborre.github.io/specs2/guide/SPECS2-3.6.6/org.specs2.guide.ExecutionEnvironments.html#implicit-executionenv) (3认同)

sub*_*oid 13

我花了一段时间才发现这个想法,我想分享一下.我应该阅读发行说明.在specs2 v3.5中,需要使用隐式ExecutionEnv来为将来使用await.这也可用于未来的转换(即地图),见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
  }
}
Run Code Online (Sandbox Code Playgroud)


Mik*_*sov 6

在specs2中有一个很好的东西 - 隐式await方法Future[Result].如果您利用未来的转换,您可以这样写:

"save notification" in {
  notificationDao.saveNotification(notification) map { writeResult =>
    writeResult.ok must be equalTo (true)
  } await
}
Run Code Online (Sandbox Code Playgroud)

当需要一些具有异步功能的数据安排时,未来的构成将得到拯救:

"get user notifications" in {
  {
    for {
      _ <- notificationDao.saveNotifications(user1Notifications)
      _ <- notificationDao.saveNotifications(user2Notifications)
      foundUser1Notifications <- notificationDao.getNotifications(user1)
    } yield {
      foundUser1Notifications must be equalTo (user1Notifications)
    }
  } await
}
Run Code Online (Sandbox Code Playgroud)

注意我们如何使用额外的块来理解以说服编译器.我认为这很吵,所以如果我们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)
  }
}
Run Code Online (Sandbox Code Playgroud)


epi*_*nal 6

Await 是一种反模式。永远不应该使用它。您可以使用诸如特质ScalaFuturesIntegrationPatienceEventually

例子:

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
            }

        }
    }
}
Run Code Online (Sandbox Code Playgroud)