在ScalaTest中无例外运行代码的单元测试

时间:2019-05-09 14:03:45

标签: scala scalatest

TL; DR我有一个Task [Unit],在ScalaTest / FlatSpec中,测试任务在给定时间内是否成功的正确方法是什么?

我有一个具有服务器-客户端体系结构的应用程序,客户端与服务器之间的交互是不阻塞的。这是通过调用客户端返回的Future来实现的,该Future在服务器完成工作后完成。重要的是,此将来不会返回结果,而只是用来指示服务器已完成:

val notification: Task[Unit] = myServer.alterState("do this")
Await.result(notification.runAsync, 20.seconds)

我这里要测试的是服务器正确地将完成通知发送给客户端。我正在使用ScalaTest的FlatSpec对此进行测试,对我来说,以下似乎是有效的测试:

"Server" should "notify client upon completion" in {
    val notification: Task[Unit] = myServer.alterState("do this")
    Await.result(notification.runAsync, 20.seconds)
}

如果服务器的回复时间超过20秒,则Await.result将引发异常,该异常将被测试捕获并失败。

这是在Flatspec中执行这种测试的正确方法吗?所有匹配的框架似乎都围绕测试结果的值,并捕获预期的异常,但是我没有返回结果,我只是想测试未来是否成功结束。

2 个答案:

答案 0 :(得分:1)

ScalaFutures可以断言Future在指定时间段内已准备就绪,例如

import org.scalatest._
import org.scalatest.concurrent.ScalaFutures
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global

class ServerSpec extends FlatSpec with ScalaFutures {
  "Server" should "notify client upon completion" in {
    val notification: Task[Unit] = myServer.alterState("do this")
    assert(notification.runAsync.isReadyWithin(20 seconds))
  }
}

AsyncFlatSpec允许使用惯用的Scala语法,我们可以像这样在Future上映射

import org.scalatest._

class ServerSpec extends AsyncFlatSpec {
  "Server" should "notify client upon completion" in {
    val notification: Task[Unit] = myServer.alterState("do this")
    notification.runAsync.map(_ => succeed)
  }
}

但是请确保服务器被设计为超时,否则测试将挂起。

FlatSpecAwait可以断言no exception应该这样抛出

import org.scalatest._
import scala.concurrent.Await
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._

class ServerSpec extends FlatSpec with Matchers {
  "Server" should "notify client upon completion" in {
    val notification: Task[Unit] = myServer.alterState("do this")
    noException should be thrownBy Await.result(notification.runAsync, 20.seconds)
  }
}

我个人建议使用AsyncFlatSpec方法。

答案 1 :(得分:0)

您可以使用intercept方法来验证是否抛出了异常。

 val notification: Task[Unit] = myServer.alterState("do this")
 notification onComplete {
   case Failure(_) => fail()
   case Success(_) => succeed
 }
 intercept[TimeoutException] { //you can also use Exception instead of TimeoutException
   Await.result(notification.runAsync, 20.seconds)
  }
  

如果您的代码引发异常,则拦截将其捕获,然后进行测试   成功。 (您希望它引发异常,但确实如此。)

更多详细信息,请参见herehere