Divverence.MarbleTesting.Akka is a small library that allows to write tests for Akka.Net actors / systems using marble diagrams in text form. This library is inspired by the practice in the Rx / ReactiveStreams world to use marble diagrams to describe the (intended) behavior of operators. It's our belief that this concept also applies very nicely to Actors in an actor model. Inspiration for this library came from the ideas of Erik Meijer and the marble test features of RxJS v5.
The purpose of the library is to help you write unit tests for your Akka.Net actors that are as readable and concise as possible.
For background on Marble Testing in general, check this nice 7 minutes introduction to RxJs testing on egghead.io.
This library is complementary to MarbleTest.Net, which targets System.Reactive (Rx.Net) specifically. Thanks go out to the author(s) of that project for ideas and possibly some source code.
You can use Divverence.MarbleTesting
in .NET and .Net Core 2 - the nuget package is available for net452
and netstardard
.
To get the lib just use nuget, from the nuget package console in Visual Studio:
PM> Install-Package Divverence.MarbleTesting
PM> Install-Package Divverence.MarbleTesting.Akka
Or add it with the dotnet CLI from cmd
, powershell
or bash
:
dotnet add package Divverence.MarbleTesting.Akka
Use pieces of code like this in your unit tests for you actors:
var marbleTest = new AkkaMarbleTest( ActorSystem );
marbleTest.WhenTelling(" --a---a---b--a-c--", disctinctActor, s => s);
marbleTest.ExpectMsgs<string>("--a-------b----c--", (s, o) => o.Should().Be(s));
await marbleTest.Run();
var marbleTest = new AkkaMarbleTest( Sys );
var throttleActor = Sys.ActorOf( ThrottleActor.Props(TimeSpan.FromSeconds(5)) );
marbleTest.WhenTelling(" --a---a-b-----c---------(d,e)---", throttleActor, s => s);
marbleTest.ExpectMsgs<string>("--a----a----b----c------d----e--", (s, o) => o.Should().Be(s));
var virtualTimeStep = TimeSpan.FromSeconds(1);
await marbleTest.Run(virtualTimeStep); // This runs in milliseconds!
The syntax for describing Sequences is compatible with the RxJS syntax. Each character represents what happens during a moment in virtual time.
'-
' means that no message is sent/received at that moment.
'a
' or any other non-reserved character means that a message is
sent or received at that moment.
So in the WhenTelling
usage, "X-Y-
" means:
- at time '
0
', a messageX
is sent, - at time '
1
', nothing is sent, - at time '
2
', a messageY
is sent, - at time '
3
', nothing is sent, - before and after time '
0
' and '3
', nothing is sent.
And in the ExpectMsg
usage, "X-Y-
" means:
- at time '
0
', a messageX
should arrive and nothing else, - at time '
1
', no message should arrive, - at time '
2
', a messageY
should arrive and nothing else, - at time '
3
', no message should arrive, - before time '
0
', nothing should arrive, - after time '
3
', no assertions are made about what should happen.
As explained above ExpectMsg
allows you to specify that a particular
message should arrive at a particular TestProbe
at a particular
moment. The 'assertion' passed has the 'marble' a string
as its
first parameter and the object/T
received by the probe. Note that
ExpectMsg
is strict in the sense that it will throw an Exception
if at the given moment any other message is received by the
TestProbe
.
WhenTelling
is the method to use to provide input to the "Subject
Under Test". The Func<string, T>
specifies what to send for which marble.
WhenDoing
is the method to use to run a particular action at a
given moment. This could be used for instance, to change something in the
environment to which your actor under test should respond.
Assert
can be used to run an assertion at a particular moment in
time. This could be used to assert that a side effect was
accomplished by the actor under test.
If messages should be sent or expected at the same time, you can group them using parenthesis.
So --(a b c)--
means events a, b and c occur at moment 2, but will (must) be in the given order.
To expect messages that can be in any order, use angle brackets <
, >
.
So --<a b c>--
means events a, b and c occur at moment 2, and the
test framework should not care about the order of the events.
For a complete description of the syntax, please refer to the official RxJS documentation
Divverence.MarbleTesting.Akka internally uses the TestKitBase.ExpectMsg
methods, and should therefore work with any of the test frameworks supported by Akka.Net.
Use dotnet CLI 2.0:
dotnet build -c Release