TestContext
A
of
and time passage, useful for testing purposes.
scala.concurrent.ExecutionContext
implementation and a providerof
cats.effect.Timer
instances, that can simulate async boundariesand time passage, useful for testing purposes.
Usage for simulating an
{{{
implicit val ec = TestContext()
ExecutionContext
):{{{
implicit val ec = TestContext()
ec.execute(new Runnable { def run() = println("task1") })
ex.execute(new Runnable {
def run() = {
println("outer")
def run() = {
println("outer")
ec.execute(new Runnable {
def run() = println("inner")
})
}
})
})
// Nothing executes until
ec.tick()
tick
gets calledec.tick()
// Testing the resulting state
assert(ec.state.tasks.isEmpty)
assert(ec.state.lastReportedFailure == None)
}}}
assert(ec.state.tasks.isEmpty)
assert(ec.state.lastReportedFailure == None)
}}}
Our
to builds a
has a
TestContext
can also simulate time passage, as we are ableto builds a
cats.effect.Timer
instance for any data type thathas a
LiftIO
instance:{{{
val ctx = TestContext()
val ctx = TestContext()
val timer: Timer[IO]
= ctx.timer[IO]
}}}
}}}
We can now simulate actual time:
{{{
val io = timer.sleep(10.seconds) *> IO(1 + 1)
val f = io.unsafeToFuture()
val io = timer.sleep(10.seconds) *> IO(1 + 1)
val f = io.unsafeToFuture()
// This invariant holds true, because our IO is async
assert(f.value == None)
assert(f.value == None)
// Not yet completed, because this does not simulate time passing:
ctx.tick()
assert(f.value == None)
ctx.tick()
assert(f.value == None)
// Simulating time passing:
ctx.tick(10.seconds)
assert(f.value == Some(Success(2))
}}}
ctx.tick(10.seconds)
assert(f.value == Some(Success(2))
}}}
Simulating time makes this pretty useful for testing race conditions:
{{{
val never = IO.async[Int] (_ => {})
val timeoutError = new TimeoutException
val timeout = timer.sleep(10.seconds) *> IO.raiseErrorInt
val never = IO.async[Int] (_ => {})
val timeoutError = new TimeoutException
val timeout = timer.sleep(10.seconds) *> IO.raiseErrorInt
val pair = (never, timeout).parMapN(_ + _)
// Not yet
ctx.tick()
assert(f.value == None)
// Not yet
ctx.tick(5.seconds)
assert(f.value == None)
ctx.tick()
assert(f.value == None)
// Not yet
ctx.tick(5.seconds)
assert(f.value == None)
// Good to go:
ctx.tick(5.seconds)
assert(f.value, Some(Failure(timeoutError)))
}}}
ctx.tick(5.seconds)
assert(f.value, Some(Failure(timeoutError)))
}}}
- Companion
- object
trait ExecutionContext
class Object
trait Matchable
class Any
Value members
Methods
Returns the internal state of the
that certain execution conditions have been met.
TestContext
, useful for testingthat certain execution conditions have been met.
Executes just one tick, one task, from the internal queue, useful
for testing that a some runnable will definitely be executed next.
for testing that a some runnable will definitely be executed next.
Returns a boolean indicating that tasks were available and that
the head of the queue has been executed, so normally you have
this equivalence:
the head of the queue has been executed, so normally you have
this equivalence:
{{{
while (ec.tickOne()) {}
// ... is equivalent with:
ec.tick()
}}}
while (ec.tickOne()) {}
// ... is equivalent with:
ec.tick()
}}}
Note that ask extraction has a random factor, the behavior being like
tick, in order to simulate nondeterminism. So you can't rely on
some ordering of execution if multiple tasks are waiting execution.
tick, in order to simulate nondeterminism. So you can't rely on
some ordering of execution if multiple tasks are waiting execution.
- Returns
-
true
if a task was available in the internal queue, and
was executed, orfalse
otherwise
Triggers execution by going through the queue of scheduled tasks and
executing them all, until no tasks remain in the queue to execute.
executing them all, until no tasks remain in the queue to execute.
Order of execution isn't guaranteed, the queued
being shuffled in order to simulate the needed nondeterminism
that happens with multi-threading.
Runnable
s arebeing shuffled in order to simulate the needed nondeterminism
that happens with multi-threading.
{{{
implicit val ec = TestContext()
implicit val ec = TestContext()
val f = Future(1 + 1).flatMap(_ + 1)
// Execution is momentarily suspended in TestContext
assert(f.value == None)
// Execution is momentarily suspended in TestContext
assert(f.value == None)
// Simulating async execution:
ec.tick()
assert(f.value, Some(Success(2)))
}}}
ec.tick()
assert(f.value, Some(Success(2)))
}}}
- Value Params
- time
-
is an optional parameter for simulating time passing;