add TestKit.setAutoPilot, see #1807
This commit is contained in:
parent
b5826f9bd9
commit
ec15fd6cfd
3 changed files with 67 additions and 3 deletions
|
|
@ -421,6 +421,14 @@ using a small example:
|
|||
.. includecode:: code/akka/docs/testkit/TestkitDocSpec.scala
|
||||
:include: imports-test-probe,my-double-echo,test-probe
|
||||
|
||||
Here a the system under test is simulated by :class:`MyDoubleEcho`, which is
|
||||
supposed to mirror its input to two outputs. Attaching two test probes enables
|
||||
verification of the (simplistic) behavior. Another example would be two actors
|
||||
A and B which collaborate by A sending messages to B. In order to verify this
|
||||
message flow, a :class:`TestProbe` could be inserted as target of A, using the
|
||||
forwarding capabilities or auto-pilot described below to include a real B in
|
||||
the test setup.
|
||||
|
||||
Probes may also be equipped with custom assertions to make your test code even
|
||||
more concise and clear:
|
||||
|
||||
|
|
@ -455,6 +463,21 @@ network functioning:
|
|||
The ``dest`` actor will receive the same message invocation as if no test probe
|
||||
had intervened.
|
||||
|
||||
Auto-Pilot
|
||||
^^^^^^^^^^
|
||||
|
||||
Receiving messages in a queue for later inspection is nice, but in order to
|
||||
keep a test running and verify traces later you can also install an
|
||||
:class:`AutoPilot` in the participating test probes (actually in any
|
||||
:class:`TestKit`) which is invoked before enqueueing to the inspection queue.
|
||||
This code can be used to forward messages, e.g. in a chain ``A --> Probe -->
|
||||
B``, as long as a certain protocol is obeyed.
|
||||
|
||||
.. includecode:: ../../akka-testkit/src/test/scala/akka/testkit/TestProbeSpec.scala#autopilot
|
||||
|
||||
The :meth:`run` method must return the auto-pilot for the next message, wrapped
|
||||
in an :class:`Option`; setting it to :obj:`None` terminates the auto-pilot.
|
||||
|
||||
Caution about Timing Assertions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
|||
|
|
@ -16,9 +16,14 @@ import akka.util.Timeout
|
|||
object TestActor {
|
||||
type Ignore = Option[PartialFunction[AnyRef, Boolean]]
|
||||
|
||||
trait AutoPilot {
|
||||
def run(sender: ActorRef, msg: Any): Option[AutoPilot]
|
||||
}
|
||||
|
||||
case class SetIgnore(i: Ignore)
|
||||
case class Watch(ref: ActorRef)
|
||||
case class UnWatch(ref: ActorRef)
|
||||
case class SetAutoPilot(ap: AutoPilot)
|
||||
|
||||
trait Message {
|
||||
def msg: AnyRef
|
||||
|
|
@ -36,11 +41,15 @@ class TestActor(queue: BlockingDeque[TestActor.Message]) extends Actor {
|
|||
|
||||
var ignore: Ignore = None
|
||||
|
||||
var autopilot: Option[AutoPilot] = None
|
||||
|
||||
def receive = {
|
||||
case SetIgnore(ign) ⇒ ignore = ign
|
||||
case x @ Watch(ref) ⇒ context.watch(ref); queue.offerLast(RealMessage(x, self))
|
||||
case x @ UnWatch(ref) ⇒ context.unwatch(ref); queue.offerLast(RealMessage(x, self))
|
||||
case SetAutoPilot(pilot) ⇒ autopilot = Some(pilot)
|
||||
case x: AnyRef ⇒
|
||||
autopilot = autopilot.flatMap(_.run(sender, x))
|
||||
val observe = ignore map (ignoreFunc ⇒ if (ignoreFunc isDefinedAt x) !ignoreFunc(x) else true) getOrElse true
|
||||
if (observe) queue.offerLast(RealMessage(x, sender))
|
||||
}
|
||||
|
|
@ -148,6 +157,13 @@ class TestKit(_system: ActorSystem) {
|
|||
expectMsg(msg)
|
||||
}
|
||||
|
||||
/**
|
||||
* Install an AutoPilot to drive the testActor: the AutoPilot will be run
|
||||
* for each received message and can be used to send or forward messages,
|
||||
* etc. Each invocation must return the AutoPilot for the next round.
|
||||
*/
|
||||
def setAutoPilot(pilot: TestActor.AutoPilot): Unit = testActor ! TestActor.SetAutoPilot(pilot)
|
||||
|
||||
/**
|
||||
* Obtain current time (`System.nanoTime`) as Duration.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -40,6 +40,31 @@ class TestProbeSpec extends AkkaSpec with DefaultTimeout {
|
|||
probe1.expectMsg(0 millis, "world")
|
||||
}
|
||||
|
||||
"have an AutoPilot" in {
|
||||
//#autopilot
|
||||
val probe = TestProbe()
|
||||
probe.setAutoPilot(new TestActor.AutoPilot {
|
||||
def run(sender: ActorRef, msg: Any): Option[TestActor.AutoPilot] =
|
||||
msg match {
|
||||
case "stop" ⇒ None
|
||||
case x ⇒ testActor.tell(x, sender); Some(this)
|
||||
}
|
||||
})
|
||||
//#autopilot
|
||||
probe.ref ! "hallo"
|
||||
probe.ref ! "welt"
|
||||
probe.ref ! "stop"
|
||||
expectMsg("hallo")
|
||||
expectMsg("welt")
|
||||
probe.expectMsg("hallo")
|
||||
probe.expectMsg("welt")
|
||||
probe.expectMsg("stop")
|
||||
probe.ref ! "hallo"
|
||||
probe.expectMsg("hallo")
|
||||
testActor ! "end"
|
||||
expectMsg("end") // verify that "hallo" did not get through
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue