Concurrent Programming

Example with Akka.Net: testing the DFS algorithm with Akka.Net TestKit

Introduction

In my first post, I introduced an example with Akka.Net by implementing an algorithm: create a tree and visit it using depth first search (DFS). In this article, we are going to test this algorithm using Akka.Net TestKit. After explaining general principles of uniting testing with Akka.Net TestKit, I will present the particular implementation used for the DFS algorithm.

Note: this example has been written using Akka.Net 1.1.2 with XUnit2, and the .Net Framework 4.6.1. The complete source code can be found on github.

How to test?

Testing one actor at a time

In order to unit test our algorithm efficiently, we need to focus on testing a small part of the code in isolation of the rest: we will test one actor at a time. First, testing more than one actors increase the difficulty to find the cause of the problem. Second, as Akka.Net is concurrent by nature, more actors can lead to more concurrent threads, and therefore our tests are more complex to understand. Third, even though integration tests are extremely important, it is not the role of unit testing. So let’s keep it simple by making small tests (at least as small as we can do) and involving only one actor per testing method.

Testing with messages only

In Akka.Net, actors do no share their state, and communicate together only with messages. To test the behavior of an actor as in reality, we need either to test if this actor has received a certain message, or if it has sent a certain message. However, there is a way to access the state of an actor in the TestKit (with TestActorRef), but the test becomes synchronous in consequence. Testing states is also important but it is not enough to test the application in real. In this article, will keep it asynchronous. For that purpose we will use TestActor and TestProbe.

Testing with mock techniques

In order to test our Actors, we will need to use the following mocking patterns.

Faking a sender with TestActor

The first scenario is simple and common. After creating an actor, we send a message to it and expect a message: this can be achieved using TestActor.

image2_fakeparent

Faking a reply-to actor in a message with TestProbe

Sometimes a message contains a reply-to IActorRef for the response. We just need to fake it using TestProbe.

image2_fakereplyto

Faking a child with TestProbe and dependency injection

Sometimes an actor reacts to a message by creating a child and sending it a message. We can test that by including a factory with the message: this is the principle of dependency injection. In the real program, the factory will create a real child. In the test program, the factory will create a probe in advance that will be accessible by the test.

image1_fakechild

Note: ICustomActorFactory and its derived classes are written in this project only, and is not provided by Akka.Net.

What to test?

A (very) short summary of my previous post

In my previous I created a tree, and visited it using the depth first search algorithm (DFS). DFS is an algorithm that visits each node of a tree in a particular order. In addition, my Akka.Net implementation of DFS had to deal with race conditions between AddRequest and VisitRequest. Finally, I also wanted to check messages consistency to verify if an AddRequest was valid before processing it (and throwing an error if not).

In order to implement all that, I created two actors: TreeActor for managing the interface between the client and the actual tree. NodeActor to represent any node of the tree. TreeActor had an IActorRef of one single NodeActor: the root of the Tree.

Finally I also needed four messages: AddRequest, AddResult, VisitRequest, VisitResult.

Here comes the to do list!

Remember that we need to test messages only, one Actor at a time. In order to (start to) be confident that my algorithm works, I am going to do the following tests.

A TreeActor should:

  • forward its requests to the Root in a simple  and valid scenario
  • throw an exception if receiving the same AddRequest twice (message consistency)
  • throw an exception if receiving an AddRequest for a non-existent child (message consistency)
  • stop sending messages while busy processing previous requests (avoid race conditions)
  • process the oldest not treated message after stopping being busy (avoid race conditions)

A NodeActor should:

  • send an AddResult to TreeActor if it is supposed to process the AddRequest
  • send an AddResult to its children if it is not supposed to process the AddRequest
  • send a VisitRequest to all its children
  • send a VisitRequest to its second child after sending it to its first child, first (message order)
  • not send a VisitRequest to its second child if waiting for a VisitResult from its first child (message order)
  • send VisitRequest to its parent after receiving VisitResult from all its children  (message order)

Let’s do this!

Instead of describing everything, I will present representative examples of each different type of tests. Of course, the complete source code can be found on github with more tests.

Testing the Tree Actor

Faking a sender with TestActor

Here we are expecting an exception (not a message). TestActor is still a the sender of the message.

Note: strangely the test above fails randomly when running all tests (it never fails individually). I think it is a bug and I should actually report it to the Akka.Net team (it might already be fixed in a later version).

Faking a child with TestProbe and dependency injection

This is the typical example:

Here we are implicitly testing the change of behavior: TreeActor is using Become internally.

Here we are nesting ExpectMsg methods because these messages are supposed to be sent in a particular chronological order.

Testing the Node Actor

Faking a reply-to actor in a message with TestProbe

This is a typical example too:

Faking a child with TestProbe and dependency injection

This example is actually also faking the sender but the fake child is more important for the test:

Here we have  three methods to test that nodes are visited in the order indicated by a depth first search.

Conclusion

I am positively impressed by Akka.Net TestKit. To be able to test a concurrent program without disabling concurrency is a major plus point. In my next articles, I will continue on presenting other aspects of this quite interesting framework.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s