When you run a specification, a
java.util.concurrent.ExecutorService is used to execute
examples concurrently. You can access this ExecutorService
to execute futures (from Scala, Scalaz etc…), by converting it to the
kind of “Execution context” required by your Future implementation.
A Scala Future needs an implicit
ExecutionContext to be created. You can get an execution
context, out of the box, shared across all specifications by declaring
it as a class member:
class MyFutureSpec(using ec: ExecutionContext) extends Specification:
def is = s2"""
Let's check this scala future ${Await.result(Future(1), Duration.Inf) must ===(1)}
"""
// in a mutable specification
class MyMutableFutureSpec(using ec: ExecutionContext) extends mutable.Specification:
"Let's check this scala future" >> {
Await.result(Future(1), Duration.Inf) must ===(1)
}
You can also use an ExecutionEnv (from now on code
examples are provided for immutable specifications only but are
transposable to mutable ones):
class MyFutureSpec(using ee: ExecutionEnv) extends Specification:
def is = s2"""
Let's check this scala future ${Await.result(Future(1), Duration.Inf) must ===(1)}
"""
This works thanks to an implicit conversion between
ExecutionEnv and ExecutionContext provided by
the
org.specs2.execute.ImplicitExecutionContextFromExecutionEnv
trait (this can be deactivated by mixing-in the
NoImplicitExecutionContextFromExecutionEnv trait).
It is actually better to use an ExecutionEnv anyway
because it is required when you want to
create
Future matchers (see the “Future” tab). Indeed
an ExecutionEnv contains a timeFactor which
can be used to modify the timeout from the command line and wait longer
for Futures executing on a continuous integration server for
example.
Future
Matchers
(see the “Future” tab) require an implicit ExecutionEnv.
This environment is used to access the timeFactor when
awaiting for Scala Futures.
The terminate matcher (see the “Termination” tab in the
optional
Matchers
section) also needs an ExecutionEnv to run a piece of code
and periodically check if it has terminated or not:
s2"""
this code must be fast enough ${
given ExecutionEnv = ExecutionEnv.fromGlobalExecutionContext
Thread.sleep(100) must terminate(retries = 1, sleep = 60.millis)
}
"""
If you want to have exactly one Env or one
ExecutionEnv per Specification you can mix-in
the org.specs2.specicication.core.OwnEnv or the
org.specs2.specicication.core.OwnExecutionEnv traits. You
will then get a specific thread pool instantiated and shutdown just for
the execution of one specification. See the
environment
page for more information.