Improving docs- removing redundant phrases (#29744)
* Improving docs- removing redundant phrases * Apply suggestions from code review Co-authored-by: Arnout Engelen <github@bzzt.net> * Making changes to improve docs Co-authored-by: Arnout Engelen <github@bzzt.net>
This commit is contained in:
parent
432d94d5a4
commit
b705ded314
3 changed files with 79 additions and 90 deletions
|
|
@ -12,7 +12,7 @@ Streams the elements through the given future flow once it successfully complete
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
Streams the elements through the given flow once the `CompletionStage` successfully completes.
|
Streams the elements through the given flow once the `CompletionStage` successfully completes.
|
||||||
If the future fails the stream is failed.
|
If the future fails the stream fails.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,10 @@ causes (i.e. exceptions) into one of the four choices given above; notably,
|
||||||
this function does not take the failed actor’s identity as an input. It is
|
this function does not take the failed actor’s identity as an input. It is
|
||||||
quite easy to come up with examples of structures where this might not seem
|
quite easy to come up with examples of structures where this might not seem
|
||||||
flexible enough, e.g. wishing for different strategies to be applied to
|
flexible enough, e.g. wishing for different strategies to be applied to
|
||||||
different subordinates. At this point it is vital to understand that
|
different subordinates. At this point, it is vital to understand that
|
||||||
supervision is about forming a recursive fault handling structure. If you try
|
supervision is about forming a recursive fault handling structure. If you try
|
||||||
to do too much at one level, it will become hard to reason about, hence the
|
to do too much at one level, it will become hard to reason about, hence the
|
||||||
recommended way in this case is to add a level of supervision.
|
recommended way, in this case, is to add a level of supervision.
|
||||||
|
|
||||||
Akka implements a specific form called “parental supervision”. Actors can only
|
Akka implements a specific form called “parental supervision”. Actors can only
|
||||||
be created by other actors—where the top-level actor is provided by the
|
be created by other actors—where the top-level actor is provided by the
|
||||||
|
|
@ -45,13 +45,13 @@ library—and each created actor is supervised by its parent. This restriction
|
||||||
makes the formation of actor supervision hierarchies implicit and encourages
|
makes the formation of actor supervision hierarchies implicit and encourages
|
||||||
sound design decisions. It should be noted that this also guarantees that
|
sound design decisions. It should be noted that this also guarantees that
|
||||||
actors cannot be orphaned or attached to supervisors from the outside, which
|
actors cannot be orphaned or attached to supervisors from the outside, which
|
||||||
might otherwise catch them unawares. In addition, this yields a natural and
|
might otherwise catch them unawares. Besides, this yields a natural and
|
||||||
clean shutdown procedure for (sub-trees of) actor applications.
|
clean shutdown procedure for (sub-trees of) actor applications.
|
||||||
|
|
||||||
@@@ warning
|
@@@ warning
|
||||||
|
|
||||||
Supervision related parent-child communication happens by special system
|
Supervision-related communication happens by special system
|
||||||
messages that have their own mailboxes separate from user messages. This
|
messages that have their mailboxes separate from user messages. This
|
||||||
implies that supervision related events are not deterministically
|
implies that supervision related events are not deterministically
|
||||||
ordered relative to ordinary messages. In general, the user cannot influence
|
ordered relative to ordinary messages. In general, the user cannot influence
|
||||||
the order of normal messages and failure notifications. For details and
|
the order of normal messages and failure notifications. For details and
|
||||||
|
|
@ -85,11 +85,10 @@ will shut down the whole actor system.
|
||||||
|
|
||||||
### `/system`: The System Guardian
|
### `/system`: The System Guardian
|
||||||
|
|
||||||
This special guardian has been introduced in order to achieve an orderly
|
This special guardian has been introduced to achieve an orderly
|
||||||
shut-down sequence where logging remains active while all normal actors
|
shut-down sequence where logging remains active while all normal actors
|
||||||
terminate, even though logging itself is implemented using actors. This is
|
terminate, even though logging itself is implemented using actors. This is
|
||||||
realized by having the system guardian watch the user guardian and initiate its own
|
realized by having the system guardian watch the user guardian and initiate its shut-down upon reception of the `Terminated` message. The top-level
|
||||||
shut-down upon reception of the `Terminated` message. The top-level
|
|
||||||
system actors are supervised using a strategy which will restart indefinitely
|
system actors are supervised using a strategy which will restart indefinitely
|
||||||
upon all types of `Exception` except for
|
upon all types of `Exception` except for
|
||||||
`ActorInitializationException` and `ActorKilledException`, which
|
`ActorInitializationException` and `ActorKilledException`, which
|
||||||
|
|
@ -128,7 +127,7 @@ children has such tight dependencies among them, that a failure of one child
|
||||||
affects the function of the others, i.e. they are inextricably linked. Since a
|
affects the function of the others, i.e. they are inextricably linked. Since a
|
||||||
restart does not clear out the mailbox, it often is best to terminate the children
|
restart does not clear out the mailbox, it often is best to terminate the children
|
||||||
upon failure and re-create them explicitly from the supervisor (by watching the
|
upon failure and re-create them explicitly from the supervisor (by watching the
|
||||||
children’s lifecycle); otherwise you have to make sure that it is no problem
|
children’s lifecycle); otherwise, you have to make sure that it is no problem
|
||||||
for any of the actors to receive a message which was queued before the restart
|
for any of the actors to receive a message which was queued before the restart
|
||||||
but processed afterwards.
|
but processed afterwards.
|
||||||
|
|
||||||
|
|
@ -137,7 +136,7 @@ automatically terminate the other children in an all-for-one strategy; this can
|
||||||
be done by watching their lifecycle: if the `Terminated` message
|
be done by watching their lifecycle: if the `Terminated` message
|
||||||
is not handled by the supervisor, it will throw a `DeathPactException`
|
is not handled by the supervisor, it will throw a `DeathPactException`
|
||||||
which (depending on its supervisor) will restart it, and the default
|
which (depending on its supervisor) will restart it, and the default
|
||||||
`preRestart` action will terminate all children. Of course this can be
|
`preRestart` action will terminate all children. Of course, this can be
|
||||||
handled explicitly as well.
|
handled explicitly as well.
|
||||||
|
|
||||||
Please note that creating one-off actors from an all-for-one supervisor entails
|
Please note that creating one-off actors from an all-for-one supervisor entails
|
||||||
|
|
@ -145,7 +144,3 @@ that failures escalated by the temporary actor will affect all the permanent
|
||||||
ones. If this is not desired, install an intermediate supervisor; this can very
|
ones. If this is not desired, install an intermediate supervisor; this can very
|
||||||
be done by declaring a router of size 1 for the worker, see
|
be done by declaring a router of size 1 for the worker, see
|
||||||
@ref:[Routing](routing.md).
|
@ref:[Routing](routing.md).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ To use Akka Testkit, you must add the following dependency in your project:
|
||||||
|
|
||||||
As with any piece of software, automated tests are a very important part of the
|
As with any piece of software, automated tests are a very important part of the
|
||||||
development cycle. The actor model presents a different view on how units of
|
development cycle. The actor model presents a different view on how units of
|
||||||
code are delimited and how they interact, which has an influence on how to
|
code are delimited and how they interact, which influences how to
|
||||||
perform tests.
|
perform tests.
|
||||||
|
|
||||||
Akka comes with a dedicated module `akka-testkit` for supporting tests.
|
Akka comes with a dedicated module `akka-testkit` for supporting tests.
|
||||||
|
|
@ -57,12 +57,12 @@ assertions detailed below. @scala[When mixing in the trait `ImplicitSender` this
|
||||||
test actor is implicitly used as sender reference when dispatching messages
|
test actor is implicitly used as sender reference when dispatching messages
|
||||||
from the test procedure.] @java[The test actor’s reference is obtained using the
|
from the test procedure.] @java[The test actor’s reference is obtained using the
|
||||||
`getRef()` method as demonstrated above.] The `testActor` may also be passed to
|
`getRef()` method as demonstrated above.] The `testActor` may also be passed to
|
||||||
other actors as usual, usually subscribing it as notification listener. There
|
other actors, as usual, usually subscribing it as notification listener. There
|
||||||
is a whole set of examination methods, e.g. receiving all consecutive messages
|
is a whole set of examination methods, e.g. receiving all consecutive messages
|
||||||
matching certain criteria, receiving a whole sequence of fixed messages or
|
matching certain criteria, receiving a whole sequence of fixed messages or
|
||||||
classes, receiving nothing for some time, etc.
|
classes, receiving nothing for some time, etc.
|
||||||
|
|
||||||
The ActorSystem passed in to the constructor of TestKit is accessible via the
|
The ActorSystem passed to the constructor of TestKit is accessible via the
|
||||||
@scala[`system` member]@java[`getSystem()` method].
|
@scala[`system` member]@java[`getSystem()` method].
|
||||||
|
|
||||||
@@@ note
|
@@@ note
|
||||||
|
|
@ -75,7 +75,7 @@ actor—are stopped.
|
||||||
|
|
||||||
### Built-In Assertions
|
### Built-In Assertions
|
||||||
|
|
||||||
The above mentioned @scala[`expectMsg`]@java[`expectMsgEquals`] is not the only method for formulating
|
The above-mentioned @scala[`expectMsg`]@java[`expectMsgEquals`] is not the only method for formulating
|
||||||
assertions concerning received messages, the full set is this:
|
assertions concerning received messages, the full set is this:
|
||||||
|
|
||||||
Scala
|
Scala
|
||||||
|
|
@ -85,7 +85,7 @@ Java
|
||||||
: @@snip [TestKitDocTest.java](/akka-docs/src/test/java/jdocs/testkit/TestKitDocTest.java) { #test-expect }
|
: @@snip [TestKitDocTest.java](/akka-docs/src/test/java/jdocs/testkit/TestKitDocTest.java) { #test-expect }
|
||||||
|
|
||||||
In these examples, the maximum durations you will find mentioned below are left
|
In these examples, the maximum durations you will find mentioned below are left
|
||||||
out, in which case they use the default value from configuration item
|
out, in which case they use the default value from the configuration item
|
||||||
`akka.test.single-expect-default` which itself defaults to 3 seconds (or they
|
`akka.test.single-expect-default` which itself defaults to 3 seconds (or they
|
||||||
obey the innermost enclosing `Within` as detailed @ref:[below](#testkit-within)). The full signatures are:
|
obey the innermost enclosing `Within` as detailed @ref:[below](#testkit-within)). The full signatures are:
|
||||||
|
|
||||||
|
|
@ -93,7 +93,7 @@ obey the innermost enclosing `Within` as detailed @ref:[below](#testkit-within))
|
||||||
The given message object must be received within the specified time; the
|
The given message object must be received within the specified time; the
|
||||||
object will be returned.
|
object will be returned.
|
||||||
* @scala[`expectMsgPF[T](d: Duration)(pf: PartialFunction[Any, T]): T`]@java[`public <T> T expectMsgPF(Duration max, String hint, Function<Object, T> f)`]
|
* @scala[`expectMsgPF[T](d: Duration)(pf: PartialFunction[Any, T]): T`]@java[`public <T> T expectMsgPF(Duration max, String hint, Function<Object, T> f)`]
|
||||||
Within the given time period, a message must be received and the given
|
Within the given time, a message must be received and the given
|
||||||
@scala[partial] function must be defined for that message; the result from applying
|
@scala[partial] function must be defined for that message; the result from applying
|
||||||
the @scala[partial] function to the received message is returned. @scala[The duration may
|
the @scala[partial] function to the received message is returned. @scala[The duration may
|
||||||
be left unspecified (empty parentheses are required in this case) to use
|
be left unspecified (empty parentheses are required in this case) to use
|
||||||
|
|
@ -125,7 +125,7 @@ instance of at least one of the supplied `Class` objects; the
|
||||||
received object will be returned. Note that this does a conformance check,
|
received object will be returned. Note that this does a conformance check,
|
||||||
if you need the class to be equal you need to verify that afterwards.
|
if you need the class to be equal you need to verify that afterwards.
|
||||||
* @scala[`expectMsgAllOf[T](d: Duration, obj: T*): Seq[T]`]@java[`public List<Object> expectMsgAllOf(Duration max, Object... msg)`]
|
* @scala[`expectMsgAllOf[T](d: Duration, obj: T*): Seq[T]`]@java[`public List<Object> expectMsgAllOf(Duration max, Object... msg)`]
|
||||||
A number of objects matching the size of the supplied object array must be
|
Several objects matching the size of the supplied object array must be
|
||||||
received within the given time, and for each of the given objects there
|
received within the given time, and for each of the given objects there
|
||||||
must exist at least one among the received ones which equals (compared with
|
must exist at least one among the received ones which equals (compared with
|
||||||
@scala[`==`]@java[`equals()`]) it. The full sequence of received objects is returned in
|
@scala[`==`]@java[`equals()`]) it. The full sequence of received objects is returned in
|
||||||
|
|
@ -134,13 +134,13 @@ the order received.
|
||||||
@@@ div { .group-scala }
|
@@@ div { .group-scala }
|
||||||
|
|
||||||
* `expectMsgAllClassOf[T](d: Duration, c: Class[_ <: T]*): Seq[T]`
|
* `expectMsgAllClassOf[T](d: Duration, c: Class[_ <: T]*): Seq[T]`
|
||||||
A number of objects matching the size of the supplied `Class` array
|
Several objects matching the size of the supplied `Class` array
|
||||||
must be received within the given time, and for each of the given classes
|
must be received within the given time, and for each of the given classes
|
||||||
there must exist at least one among the received objects whose class equals
|
there must exist at least one among the received objects whose class equals
|
||||||
(compared with `==`) it (this is *not* a conformance check). The full
|
(compared with `==`) it (this is *not* a conformance check). The full
|
||||||
sequence of received objects is returned.
|
sequence of received objects is returned.
|
||||||
* `expectMsgAllConformingOf[T](d: Duration, c: Class[_ <: T]*): Seq[T]`
|
* `expectMsgAllConformingOf[T](d: Duration, c: Class[_ <: T]*): Seq[T]`
|
||||||
A number of objects matching the size of the supplied `Class` array
|
Several objects matching the size of the supplied `Class` array
|
||||||
must be received within the given time, and for each of the given classes
|
must be received within the given time, and for each of the given classes
|
||||||
there must exist at least one among the received objects which is an
|
there must exist at least one among the received objects which is an
|
||||||
instance of this class. The full sequence of received objects is returned.
|
instance of this class. The full sequence of received objects is returned.
|
||||||
|
|
@ -185,7 +185,7 @@ Collect messages as long as
|
||||||
All collected messages are returned. @scala[The maximum duration defaults to the
|
All collected messages are returned. @scala[The maximum duration defaults to the
|
||||||
time remaining in the innermost enclosing @ref:[within](#testkit-within)
|
time remaining in the innermost enclosing @ref:[within](#testkit-within)
|
||||||
block and the idle duration defaults to infinity (thereby disabling the
|
block and the idle duration defaults to infinity (thereby disabling the
|
||||||
idle timeout feature). The number of expected messages defaults to
|
idle-timeout feature). The number of expected messages defaults to
|
||||||
`Int.MaxValue`, which effectively disables this limit.]
|
`Int.MaxValue`, which effectively disables this limit.]
|
||||||
|
|
||||||
* @scala[`awaitCond(p: => Boolean, max: Duration, interval: Duration)`]@java[`public void awaitCond(Duration max, Duration interval, Supplier<Boolean> p)`]
|
* @scala[`awaitCond(p: => Boolean, max: Duration, interval: Duration)`]@java[`public void awaitCond(Duration max, Duration interval, Supplier<Boolean> p)`]
|
||||||
|
|
@ -217,7 +217,7 @@ to ignore regular messages and are only interested in your specific ones.]
|
||||||
|
|
||||||
### Expecting Log Messages
|
### Expecting Log Messages
|
||||||
|
|
||||||
Since an integration test does not allow to the internal processing of the
|
Since an integration test does not allow observing the internal processing of the
|
||||||
participating actors, verifying expected exceptions cannot be done directly.
|
participating actors, verifying expected exceptions cannot be done directly.
|
||||||
Instead, use the logging system for this purpose: replacing the normal event
|
Instead, use the logging system for this purpose: replacing the normal event
|
||||||
handler with the `TestEventListener` and using an `EventFilter`
|
handler with the `TestEventListener` and using an `EventFilter`
|
||||||
|
|
@ -230,7 +230,7 @@ Scala
|
||||||
Java
|
Java
|
||||||
: @@snip [TestKitDocTest.java](/akka-docs/src/test/java/jdocs/testkit/TestKitDocTest.java) { #test-event-filter }
|
: @@snip [TestKitDocTest.java](/akka-docs/src/test/java/jdocs/testkit/TestKitDocTest.java) { #test-event-filter }
|
||||||
|
|
||||||
If a number of occurrences is specific—as demonstrated above—then `intercept`
|
If the number of occurrences is specific—as demonstrated above—then `intercept`
|
||||||
will block until that number of matching messages have been received or the
|
will block until that number of matching messages have been received or the
|
||||||
timeout configured in `akka.test.filter-leeway` is used up (time starts
|
timeout configured in `akka.test.filter-leeway` is used up (time starts
|
||||||
counting after the passed-in block of code returns). In case of a timeout the
|
counting after the passed-in block of code returns). In case of a timeout the
|
||||||
|
|
@ -251,7 +251,7 @@ akka.loggers = [akka.testkit.TestEventListener]
|
||||||
### Overriding behavior
|
### Overriding behavior
|
||||||
|
|
||||||
Sometimes you want to 'hook into' your actor to be able to test some internals.
|
Sometimes you want to 'hook into' your actor to be able to test some internals.
|
||||||
Usually it is better to test an actors' external interface, but for example if
|
Usually, it is better to test an actors' external interface, but for example if
|
||||||
you want to test timing-sensitive behavior this can come in handy. Say for
|
you want to test timing-sensitive behavior this can come in handy. Say for
|
||||||
instance you want to test an actor that schedules a task:
|
instance you want to test an actor that schedules a task:
|
||||||
|
|
||||||
|
|
@ -294,7 +294,7 @@ you do not specify it, it is inherited from the innermost enclosing
|
||||||
|
|
||||||
It should be noted that if the last message-receiving assertion of the block is
|
It should be noted that if the last message-receiving assertion of the block is
|
||||||
`expectNoMessage` or `receiveWhile`, the final check of the
|
`expectNoMessage` or `receiveWhile`, the final check of the
|
||||||
`within` is skipped in order to avoid false positives due to wake-up
|
`within` is skipped to avoid false positives due to wake-up
|
||||||
latencies. This means that while individual contained assertions still use the
|
latencies. This means that while individual contained assertions still use the
|
||||||
maximum time bound, the overall block may take arbitrarily longer in this case.
|
maximum time bound, the overall block may take arbitrarily longer in this case.
|
||||||
|
|
||||||
|
|
@ -347,7 +347,7 @@ If you want the sender of messages inside your TestKit-based tests to be the `te
|
||||||
When the actors under test are supposed to send various messages to different
|
When the actors under test are supposed to send various messages to different
|
||||||
destinations, it may be difficult distinguishing the message streams arriving
|
destinations, it may be difficult distinguishing the message streams arriving
|
||||||
at the `testActor` when using the `TestKit` as @scala[a mixin]@java[shown until now]. Another
|
at the `testActor` when using the `TestKit` as @scala[a mixin]@java[shown until now]. Another
|
||||||
approach is to use it for creation of simple probe actors to be inserted in the
|
approach is to use it for the creation of simple probe actors to be inserted in the
|
||||||
message flows. @scala[To make this more powerful and convenient, there is a concrete
|
message flows. @scala[To make this more powerful and convenient, there is a concrete
|
||||||
implementation called `TestProbe`.] The functionality is best explained
|
implementation called `TestProbe`.] The functionality is best explained
|
||||||
using a small example:
|
using a small example:
|
||||||
|
|
@ -364,8 +364,8 @@ Java
|
||||||
supposed to mirror its input to two outputs. Attaching two test probes enables
|
supposed to mirror its input to two outputs. Attaching two test probes enables
|
||||||
verification of the (simplistic) behavior]@java[This simple test verifies an equally simple Forwarder actor by injecting a
|
verification of the (simplistic) behavior]@java[This simple test verifies an equally simple Forwarder actor by injecting a
|
||||||
probe as the forwarder’s target]. Another example would be two actors
|
probe as the forwarder’s target]. Another example would be two actors
|
||||||
A and B which collaborate by A sending messages to B. In order to verify this
|
A and B which collaborate by A sending messages to B. To verify this
|
||||||
message flow, a `TestProbe` could be inserted as target of A, using the
|
message flow, a `TestProbe` could be inserted as a target of A, using the
|
||||||
forwarding capabilities or auto-pilot described below to include a real B in
|
forwarding capabilities or auto-pilot described below to include a real B in
|
||||||
the test setup.
|
the test setup.
|
||||||
|
|
||||||
|
|
@ -388,16 +388,16 @@ Java
|
||||||
: @@snip [TestKitDocTest.java](/akka-docs/src/test/java/jdocs/testkit/TestKitDocTest.java) { #test-special-probe }
|
: @@snip [TestKitDocTest.java](/akka-docs/src/test/java/jdocs/testkit/TestKitDocTest.java) { #test-special-probe }
|
||||||
|
|
||||||
You have complete flexibility here in mixing and matching the `TestKit`
|
You have complete flexibility here in mixing and matching the `TestKit`
|
||||||
facilities with your own checks and choosing an intuitive name for it. In real
|
facilities with your checks and choosing an intuitive name for it. In real
|
||||||
life your code will probably be a bit more complicated than the example given
|
life your code will probably be a bit more complicated than the example given
|
||||||
above; just use the power!
|
above; just use the power!
|
||||||
|
|
||||||
@@@ warning
|
@@@ warning
|
||||||
|
|
||||||
Any message sent from a `TestProbe` to another actor which runs on the
|
Any message sent from a `TestProbe` to another actor which runs on the
|
||||||
CallingThreadDispatcher runs the risk of dead-lock, if that other actor might
|
CallingThreadDispatcher runs the risk of dead-lock if that other actor might
|
||||||
also send to this probe. The implementation of `TestProbe.watch` and
|
also send to this probe. The implementation of `TestProbe.watch` and
|
||||||
`TestProbe.unwatch` will also send a message to the watchee, which
|
`TestProbe.unwatch` will also send a message to the actor being watched, which
|
||||||
means that it is dangerous to try watching e.g. `TestActorRef` from a
|
means that it is dangerous to try watching e.g. `TestActorRef` from a
|
||||||
`TestProbe`.
|
`TestProbe`.
|
||||||
|
|
||||||
|
|
@ -448,7 +448,7 @@ had intervened.]
|
||||||
|
|
||||||
#### Auto-Pilot
|
#### Auto-Pilot
|
||||||
|
|
||||||
Receiving messages in a queue for later inspection is nice, but in order to
|
Receiving messages in a queue for later inspection is nice, but to
|
||||||
keep a test running and verify traces later you can also install an
|
keep a test running and verify traces later you can also install an
|
||||||
`AutoPilot` in the participating test probes (actually in any
|
`AutoPilot` in the participating test probes (actually in any
|
||||||
`TestKit`) which is invoked before enqueueing to the inspection queue.
|
`TestKit`) which is invoked before enqueueing to the inspection queue.
|
||||||
|
|
@ -462,7 +462,7 @@ Java
|
||||||
: @@snip [TestKitDocTest.java](/akka-docs/src/test/java/jdocs/testkit/TestKitDocTest.java) { #test-auto-pilot }
|
: @@snip [TestKitDocTest.java](/akka-docs/src/test/java/jdocs/testkit/TestKitDocTest.java) { #test-auto-pilot }
|
||||||
|
|
||||||
The `run` method must return the auto-pilot for the next message, @scala[which
|
The `run` method must return the auto-pilot for the next message, @scala[which
|
||||||
may be `KeepRunning` to retain the current one or `NoAutoPilot`
|
can be `KeepRunning` to retain the current one or `NoAutoPilot`
|
||||||
to switch it off]@java[wrapped
|
to switch it off]@java[wrapped
|
||||||
in an `Option`; setting it to `None` terminates the auto-pilot].
|
in an `Option`; setting it to `None` terminates the auto-pilot].
|
||||||
|
|
||||||
|
|
@ -471,7 +471,7 @@ in an `Option`; setting it to `None` terminates the auto-pilot].
|
||||||
The behavior of `within` blocks when using test probes might be perceived
|
The behavior of `within` blocks when using test probes might be perceived
|
||||||
as counter-intuitive: you need to remember that the nicely scoped deadline as
|
as counter-intuitive: you need to remember that the nicely scoped deadline as
|
||||||
described @ref:[above](#testkit-within) is local to each probe. Hence, probes
|
described @ref:[above](#testkit-within) is local to each probe. Hence, probes
|
||||||
do not react to each other's deadlines or to the deadline set in an enclosing
|
do not react to each other's deadlines or the deadline set in an enclosing
|
||||||
`TestKit` instance:
|
`TestKit` instance:
|
||||||
|
|
||||||
Scala
|
Scala
|
||||||
|
|
@ -486,7 +486,7 @@ Here, the @scala[`expectMsg`]@java[`expectMsgEquals`] call will use the default
|
||||||
|
|
||||||
The parent of an actor is always the actor that created it. At times this leads to
|
The parent of an actor is always the actor that created it. At times this leads to
|
||||||
a coupling between the two that may not be straightforward to test.
|
a coupling between the two that may not be straightforward to test.
|
||||||
There are several approaches to improve testability of a child actor that
|
There are several approaches to improve the testability of a child actor that
|
||||||
needs to refer to its parent:
|
needs to refer to its parent:
|
||||||
|
|
||||||
1. when creating a child, pass an explicit reference to its parent
|
1. when creating a child, pass an explicit reference to its parent
|
||||||
|
|
@ -505,9 +505,9 @@ Scala
|
||||||
Java
|
Java
|
||||||
: @@snip [ParentChildTest.java](/akka-docs/src/test/java/jdocs/testkit/ParentChildTest.java) { #test-example }
|
: @@snip [ParentChildTest.java](/akka-docs/src/test/java/jdocs/testkit/ParentChildTest.java) { #test-example }
|
||||||
|
|
||||||
#### Introduce child to its parent
|
#### Introduce a child to its parent
|
||||||
|
|
||||||
The first option is to avoid use of the `context.parent` function and create
|
The first option is to avoid the use of the `context.parent` function and create
|
||||||
a child with a custom parent by passing an explicit reference to its parent instead.
|
a child with a custom parent by passing an explicit reference to its parent instead.
|
||||||
|
|
||||||
Scala
|
Scala
|
||||||
|
|
@ -518,7 +518,7 @@ Java
|
||||||
|
|
||||||
#### Create the child using @scala[TestProbe]@java[TestKit]
|
#### Create the child using @scala[TestProbe]@java[TestKit]
|
||||||
|
|
||||||
The @scala[`TestProbe`]@java[`TestKit`] class can in fact create actors that will run with the test probe as parent.
|
The @scala[`TestProbe`]@java[`TestKit`] class can create actors that will run with the test probe as a parent.
|
||||||
This will cause any messages the child actor sends to @scala[*context.parent*]@java[*getContext().getParent()*] to
|
This will cause any messages the child actor sends to @scala[*context.parent*]@java[*getContext().getParent()*] to
|
||||||
end up in the test probe.
|
end up in the test probe.
|
||||||
|
|
||||||
|
|
@ -580,7 +580,7 @@ The `CallingThreadDispatcher` runs invocations on the current thread only. This
|
||||||
dispatcher does not create any new threads.
|
dispatcher does not create any new threads.
|
||||||
|
|
||||||
It is possible to use the `CallingThreadDispatcher` in unit testing, as
|
It is possible to use the `CallingThreadDispatcher` in unit testing, as
|
||||||
described above, but originally it was conceived in order to allow contiguous
|
described above, but originally it was conceived to allow uninterrupted
|
||||||
stack traces to be generated in case of an error. As this special dispatcher
|
stack traces to be generated in case of an error. As this special dispatcher
|
||||||
runs everything which would normally be queued directly on the current thread,
|
runs everything which would normally be queued directly on the current thread,
|
||||||
the full history of a message's processing chain is recorded on the call stack,
|
the full history of a message's processing chain is recorded on the call stack,
|
||||||
|
|
@ -600,7 +600,7 @@ Java
|
||||||
|
|
||||||
When receiving an invocation, the `CallingThreadDispatcher` checks
|
When receiving an invocation, the `CallingThreadDispatcher` checks
|
||||||
whether the receiving actor is already active on the current thread. The
|
whether the receiving actor is already active on the current thread. The
|
||||||
simplest example for this situation is an actor which sends a message to
|
simplest example of this situation is an actor which sends a message to
|
||||||
itself. In this case, processing cannot continue immediately as that would
|
itself. In this case, processing cannot continue immediately as that would
|
||||||
violate the actor model, so the invocation is queued and will be processed when
|
violate the actor model, so the invocation is queued and will be processed when
|
||||||
the active invocation on that actor finishes its processing; thus, it will be
|
the active invocation on that actor finishes its processing; thus, it will be
|
||||||
|
|
@ -612,12 +612,12 @@ also executed immediately.
|
||||||
This scheme makes the `CallingThreadDispatcher` work like a general
|
This scheme makes the `CallingThreadDispatcher` work like a general
|
||||||
purpose dispatcher for any actors which never block on external events.
|
purpose dispatcher for any actors which never block on external events.
|
||||||
|
|
||||||
In the presence of multiple threads it may happen that two invocations of an
|
In the presence of multiple threads, it may happen that two invocations of an
|
||||||
actor running on this dispatcher happen on two different threads at the same
|
actor running on this dispatcher happen on two different threads at the same
|
||||||
time. In this case, both will be processed directly on their respective
|
time. In this case, both will be processed directly on their respective
|
||||||
threads, where both compete for the actor's lock and the loser has to wait.
|
threads, where both compete for the actor's lock and the loser has to wait.
|
||||||
Thus, the actor model is left intact, but the price is loss of concurrency due
|
Thus, the actor model is left intact, but the price is the loss of concurrency due
|
||||||
to limited scheduling. In a sense this is equivalent to traditional mutex style
|
to limited scheduling. In a sense, this is equivalent to traditional mutex style
|
||||||
concurrency.
|
concurrency.
|
||||||
|
|
||||||
The other remaining difficulty is correct handling of suspend and resume: when
|
The other remaining difficulty is correct handling of suspend and resume: when
|
||||||
|
|
@ -627,24 +627,23 @@ queues (the same ones used for queuing in the normal case). The call to
|
||||||
in the system will probably not be executing this specific actor, which leads
|
in the system will probably not be executing this specific actor, which leads
|
||||||
to the problem that the thread-local queues cannot be emptied by their native
|
to the problem that the thread-local queues cannot be emptied by their native
|
||||||
threads. Hence, the thread calling `resume` will collect all currently
|
threads. Hence, the thread calling `resume` will collect all currently
|
||||||
queued invocations from all threads into its own queue and process them.
|
queued invocations from all threads into its queue and process them.
|
||||||
|
|
||||||
### Limitations
|
### Limitations
|
||||||
|
|
||||||
@@@ warning
|
@@@ warning
|
||||||
|
|
||||||
In case the CallingThreadDispatcher is used for top-level actors, but
|
In case the CallingThreadDispatcher is used for top-level actors,
|
||||||
without going through TestActorRef, then there is a time window during which
|
without going through TestActorRef, then there is a time window during which
|
||||||
the actor is awaiting construction by the user guardian actor. Sending
|
the actor is awaiting construction by the user guardian actor. Sending
|
||||||
messages to the actor during this time period will result in them being
|
messages to the actor during this time will result in them being
|
||||||
enqueued and then executed on the guardian’s thread instead of the caller’s
|
enqueued and then executed on the guardian’s thread instead of the caller’s
|
||||||
thread. To avoid this, use TestActorRef.
|
thread. To avoid this, use TestActorRef.
|
||||||
|
|
||||||
@@@
|
@@@
|
||||||
|
|
||||||
If an actor's behavior blocks on a something which would normally be affected
|
If an actor's behavior blocks on something which would normally be affected
|
||||||
by the calling actor after having sent the message, this will obviously
|
by the calling actor after having sent the message, this will dead-lock when using this dispatcher. This is a common scenario in actor tests
|
||||||
dead-lock when using this dispatcher. This is a common scenario in actor tests
|
|
||||||
based on `CountDownLatch` for synchronization:
|
based on `CountDownLatch` for synchronization:
|
||||||
|
|
||||||
```scala
|
```scala
|
||||||
|
|
@ -661,8 +660,8 @@ normal dispatcher.
|
||||||
Thus, keep in mind that the `CallingThreadDispatcher` is not a
|
Thus, keep in mind that the `CallingThreadDispatcher` is not a
|
||||||
general-purpose replacement for the normal dispatchers. If you are looking
|
general-purpose replacement for the normal dispatchers. If you are looking
|
||||||
for a tool to help you debug dead-locks,
|
for a tool to help you debug dead-locks,
|
||||||
the `CallingThreadDispatcher` may help with certain error
|
the `CallingThreadDispatcher` may help with some error
|
||||||
scenarios, but keep in mind that it has may give false negatives as well as
|
scenarios, but keep in mind that it may give false negatives as well as
|
||||||
false positives.
|
false positives.
|
||||||
|
|
||||||
### Thread Interruptions
|
### Thread Interruptions
|
||||||
|
|
@ -681,7 +680,7 @@ thread’s interrupted flag will be set and processing continues normally.
|
||||||
|
|
||||||
@@@ note
|
@@@ note
|
||||||
|
|
||||||
The summary of these two paragraphs is that if the current thread is
|
In summary, if the current thread is
|
||||||
interrupted while doing work under the CallingThreadDispatcher, then that
|
interrupted while doing work under the CallingThreadDispatcher, then that
|
||||||
will result in the `isInterrupted` flag to be `true` when the message
|
will result in the `isInterrupted` flag to be `true` when the message
|
||||||
send returns and no `InterruptedException` will be thrown.
|
send returns and no `InterruptedException` will be thrown.
|
||||||
|
|
@ -690,7 +689,7 @@ send returns and no `InterruptedException` will be thrown.
|
||||||
|
|
||||||
### Benefits
|
### Benefits
|
||||||
|
|
||||||
To summarize, these are the features with the `CallingThreadDispatcher`
|
To summarize, these are the features that `CallingThreadDispatcher`
|
||||||
has to offer:
|
has to offer:
|
||||||
|
|
||||||
* Deterministic execution of single-threaded tests while retaining nearly full
|
* Deterministic execution of single-threaded tests while retaining nearly full
|
||||||
|
|
@ -709,7 +708,7 @@ by debuggers as well as logging, where the Akka toolkit offers the following
|
||||||
options:
|
options:
|
||||||
|
|
||||||
* *Logging of exceptions thrown within Actor instances*
|
* *Logging of exceptions thrown within Actor instances*
|
||||||
This is always on; in contrast to the other logging mechanisms, this logs at
|
It is always on; in contrast to the other logging mechanisms, this logs at
|
||||||
`ERROR` level.
|
`ERROR` level.
|
||||||
|
|
||||||
@@@ div { .group-scala }
|
@@@ div { .group-scala }
|
||||||
|
|
@ -722,7 +721,7 @@ statement to be applied to an actor’s `receive` function:
|
||||||
|
|
||||||
If the aforementioned setting is not given in the @ref:[Configuration](general/configuration-reference.md#config-akka-actor), this method will
|
If the aforementioned setting is not given in the @ref:[Configuration](general/configuration-reference.md#config-akka-actor), this method will
|
||||||
pass through the given `Receive` function unmodified, meaning that
|
pass through the given `Receive` function unmodified, meaning that
|
||||||
there is no runtime cost unless actually enabled.
|
there is no runtime cost unless enabled.
|
||||||
|
|
||||||
The logging feature is coupled to this specific local mark-up because
|
The logging feature is coupled to this specific local mark-up because
|
||||||
enabling it uniformly on all actors is not usually what you need, and it
|
enabling it uniformly on all actors is not usually what you need, and it
|
||||||
|
|
@ -740,7 +739,7 @@ actors.
|
||||||
enabling the setting `akka.actor.debug.lifecycle`; this, too, is enabled
|
enabling the setting `akka.actor.debug.lifecycle`; this, too, is enabled
|
||||||
uniformly on all actors.
|
uniformly on all actors.
|
||||||
|
|
||||||
All these messages are logged at `DEBUG` level. To summarize, you can enable
|
Logging of these messages is at `DEBUG` level. To summarize, you can enable
|
||||||
full logging of actor activities using this configuration fragment:
|
full logging of actor activities using this configuration fragment:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
@ -760,13 +759,13 @@ akka {
|
||||||
|
|
||||||
## Different Testing Frameworks
|
## Different Testing Frameworks
|
||||||
|
|
||||||
Akka’s own test suite is written using [ScalaTest](http://www.scalatest.org),
|
Akka’s test suite is written using [ScalaTest](http://www.scalatest.org),
|
||||||
which also shines through in documentation examples. However, the TestKit and
|
which also shines through in documentation examples. However, the TestKit and
|
||||||
its facilities do not depend on that framework, you can essentially use
|
its facilities do not depend on that framework, so you can essentially use
|
||||||
whichever suits your development style best.
|
whichever suits your development style best.
|
||||||
|
|
||||||
This section contains a collection of known gotchas with some other frameworks,
|
This section contains a collection of known gotchas with some other frameworks,
|
||||||
which is by no means exhaustive and does not imply endorsement or special
|
which is by no means exhaustive and does not imply an endorsement or special
|
||||||
support.
|
support.
|
||||||
|
|
||||||
### When you need it to be a trait
|
### When you need it to be a trait
|
||||||
|
|
@ -788,21 +787,17 @@ backwards compatibility in the future, use at own risk.
|
||||||
Some [Specs2](https://etorreborre.github.io/specs2/) users have contributed examples of how to work around some clashes which may arise:
|
Some [Specs2](https://etorreborre.github.io/specs2/) users have contributed examples of how to work around some clashes which may arise:
|
||||||
|
|
||||||
* Mixing TestKit into `org.specs2.mutable.Specification` results in a
|
* Mixing TestKit into `org.specs2.mutable.Specification` results in a
|
||||||
name clash involving the `end` method (which is a private variable in
|
name clash involving the `end` method (which is a private variable in
|
||||||
TestKit and an abstract method in Specification); if mixing in TestKit first,
|
TestKit and an abstract method in Specification); if mixing in TestKit first,
|
||||||
the code may compile but might then fail at runtime. The work-around—which is
|
the code may compile but might then fail at runtime. The workaround—which is
|
||||||
actually beneficial also for the third point—is to apply the TestKit together
|
beneficial also for the third point—is to apply the TestKit together
|
||||||
with `org.specs2.specification.Scope`.
|
with `org.specs2.specification.Scope`.
|
||||||
* The Specification traits provide a `Duration` DSL which uses partly
|
* The Specification traits provide a `Duration` DSL which uses partly the same method names as `scala.concurrent.duration.Duration`, resulting in ambiguous implicits if `scala.concurrent.duration._` is imported. There are two workarounds:
|
||||||
the same method names as `scala.concurrent.duration.Duration`, resulting in ambiguous
|
* either use the Specification variant of Duration and supply an implicit conversion to the Akka Duration. This conversion is not supplied with the
|
||||||
implicits if `scala.concurrent.duration._` is imported. There are two workarounds:
|
Akka distribution because that would mean that our JAR files would depend on
|
||||||
* either use the Specification variant of Duration and supply an implicit
|
Specs2, which is not justified by this little feature.
|
||||||
conversion to the Akka Duration. This conversion is not supplied with the
|
* or mix `org.specs2.time.NoTimeConversions` into the Specification.
|
||||||
Akka distribution because that would mean that our JAR files would depend on
|
* Specifications are by default executed concurrently, which requires some care when writing the tests or the `sequential` keyword.
|
||||||
Specs2, which is not justified by this little feature.
|
|
||||||
* or mix `org.specs2.time.NoTimeConversions` into the Specification.
|
|
||||||
* Specifications are by default executed concurrently, which requires some care
|
|
||||||
when writing the tests or alternatively the `sequential` keyword.
|
|
||||||
|
|
||||||
@@@
|
@@@
|
||||||
|
|
||||||
|
|
@ -835,12 +830,11 @@ integration tests.
|
||||||
|
|
||||||
Normally, the `ActorRef` shields the underlying `Actor` instance
|
Normally, the `ActorRef` shields the underlying `Actor` instance
|
||||||
from the outside, the only communications channel is the actor's mailbox. This
|
from the outside, the only communications channel is the actor's mailbox. This
|
||||||
restriction is an impediment to unit testing, which led to the inception of the
|
restriction impedes unit testing, which led to the inception of the
|
||||||
`TestActorRef`. This special type of reference is designed specifically
|
`TestActorRef`. This special type of reference is designed specifically
|
||||||
for test purposes and allows access to the actor in two ways: either by
|
for test purposes and allows access to the actor in two ways: either by
|
||||||
obtaining a reference to the underlying actor instance, or by invoking or
|
obtaining a reference to the underlying actor instance or by invoking or
|
||||||
querying the actor's behavior (`receive`). Each one warrants its own
|
querying the actor's behavior (`receive`). Each one warrants its section below.
|
||||||
section below.
|
|
||||||
|
|
||||||
@@@ note
|
@@@ note
|
||||||
|
|
||||||
|
|
@ -852,7 +846,7 @@ instead of using `TestActorRef` whenever possible.
|
||||||
|
|
||||||
@@@ warning
|
@@@ warning
|
||||||
|
|
||||||
Due to the synchronous nature of `TestActorRef` it will **not** work with some support
|
Due to the synchronous nature of `TestActorRef`, it will **not** work with some support
|
||||||
traits that Akka provides as they require asynchronous behaviors to function properly.
|
traits that Akka provides as they require asynchronous behaviors to function properly.
|
||||||
Examples of traits that do not mix well with test actor refs are @ref:[PersistentActor](persistence.md#example)
|
Examples of traits that do not mix well with test actor refs are @ref:[PersistentActor](persistence.md#example)
|
||||||
and @ref:[AtLeastOnceDelivery](persistence.md#at-least-once-delivery) provided by @ref:[Akka Persistence](persistence.md).
|
and @ref:[AtLeastOnceDelivery](persistence.md#at-least-once-delivery) provided by @ref:[Akka Persistence](persistence.md).
|
||||||
|
|
@ -861,7 +855,7 @@ and @ref:[AtLeastOnceDelivery](persistence.md#at-least-once-delivery) provided b
|
||||||
|
|
||||||
### Obtaining a Reference to an `Actor`
|
### Obtaining a Reference to an `Actor`
|
||||||
|
|
||||||
Having access to the actual `Actor` object allows application of all
|
Having access to the actual `Actor` object allows the application of all
|
||||||
traditional unit testing techniques on the contained methods. Obtaining a
|
traditional unit testing techniques on the contained methods. Obtaining a
|
||||||
reference is done like this:
|
reference is done like this:
|
||||||
|
|
||||||
|
|
@ -881,9 +875,9 @@ any unit testing tool to bear on your actor as usual.
|
||||||
<a id="testfsmref"></a>
|
<a id="testfsmref"></a>
|
||||||
### Testing Finite State Machines
|
### Testing Finite State Machines
|
||||||
|
|
||||||
If your actor under test is a `FSM`, you may use the special
|
If your actor under test is an `FSM`, you may use the special
|
||||||
`TestFSMRef` which offers all features of a normal `TestActorRef`
|
`TestFSMRef` which offers all features of a normal `TestActorRef`
|
||||||
and in addition allows access to the internal state:
|
and besides allows access to the internal state:
|
||||||
|
|
||||||
@@snip [TestkitDocSpec.scala](/akka-docs/src/test/scala/docs/testkit/TestkitDocSpec.scala) { #test-fsm-ref }
|
@@snip [TestkitDocSpec.scala](/akka-docs/src/test/scala/docs/testkit/TestkitDocSpec.scala) { #test-fsm-ref }
|
||||||
|
|
||||||
|
|
@ -893,7 +887,7 @@ instead of the hypothetical `ActorRef`-inspired `TestFSMRef[MyFSM]`.
|
||||||
All methods shown above directly access the FSM state without any
|
All methods shown above directly access the FSM state without any
|
||||||
synchronization; this is perfectly alright if the `CallingThreadDispatcher`
|
synchronization; this is perfectly alright if the `CallingThreadDispatcher`
|
||||||
is used and no other threads are involved, but it may lead to surprises if you
|
is used and no other threads are involved, but it may lead to surprises if you
|
||||||
were to actually exercise timer events, because those are executed on the
|
were to exercise timer events, because those are executed on the
|
||||||
`Scheduler` thread.
|
`Scheduler` thread.
|
||||||
|
|
||||||
@@@
|
@@@
|
||||||
|
|
@ -901,8 +895,8 @@ were to actually exercise timer events, because those are executed on the
|
||||||
### Testing the Actor's Behavior
|
### Testing the Actor's Behavior
|
||||||
|
|
||||||
When the dispatcher invokes the processing behavior of an actor on a message,
|
When the dispatcher invokes the processing behavior of an actor on a message,
|
||||||
it actually calls `apply` on the current behavior registered for the
|
it calls `apply` on the current behavior registered for the
|
||||||
actor. This starts out with the return value of the declared `receive`
|
actor. This starts with the return value of the declared `receive`
|
||||||
method, but it may also be changed using `become` and `unbecome` in
|
method, but it may also be changed using `become` and `unbecome` in
|
||||||
response to external messages. All of this contributes to the overall actor
|
response to external messages. All of this contributes to the overall actor
|
||||||
behavior and it does not lend itself to easy testing on the `Actor`
|
behavior and it does not lend itself to easy testing on the `Actor`
|
||||||
|
|
@ -942,7 +936,7 @@ dispatcher to `CallingThreadDispatcher.global` and it sets the
|
||||||
|
|
||||||
### The Way In-Between: Expecting Exceptions
|
### The Way In-Between: Expecting Exceptions
|
||||||
|
|
||||||
If you want to test the actor behavior, including hotswapping, but without
|
If you want to test the actor behavior, including hot swapping, but without
|
||||||
involving a dispatcher and without having the `TestActorRef` swallow
|
involving a dispatcher and without having the `TestActorRef` swallow
|
||||||
any thrown exceptions, then there is another mode available for you: use
|
any thrown exceptions, then there is another mode available for you: use
|
||||||
the `receive` method on `TestActorRef`, which will be forwarded to the
|
the `receive` method on `TestActorRef`, which will be forwarded to the
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue