TL;DR I have a Task[Unit], in ScalaTest/FlatSpec what is the proper way to test if the task succeeded in a given time frame?
I have an application with a server-client architecture, the interaction between client and server is non blocking. This is implemented by calls on the client returning a future which completes when the server has finished the work. Importantly this future does not return back the result, it is just used to indicate that the server has finished:
val notification: Task[Unit] = myServer.alterState("do this")
Await.result(notification.runAsync, 20.seconds)
What I want to test here is that the server is correctly sending notifications of completion to the client. I'm testing this with FlatSpec from ScalaTest, and to me it seems that the following should be a valid test:
"Server" should "notify client upon completion" in {
val notification: Task[Unit] = myServer.alterState("do this")
Await.result(notification.runAsync, 20.seconds)
}
If the server takes longer than 20 seconds to reply, Await.result will throw an exception, which the test will catch, and fail.
Is this the correct way to perform this sort of test in flatspec? All of the matching framework seems to be geared around testing the value of results, and catching expected exceptions, but I don't have a result returned, I just want to test that the future ends successfully.
ScalaFutures
enable to assert a Future
is ready within a a specified time period like so
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 allows for idiomatic Scala syntax where we can map over Future
like so
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)
}
}
but make sure server is designed to timeout, otherwise test will hang.
FlatSpec
with Await
could assert explicitly no exception should be thrown like so
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)
}
}
Personally, I would recommend AsyncFlatSpec
method.