Thoughts, Tips and Tricks on what I'm currently do for a living. Currently most of my spare time is spent on contributing to Akka.NET.
Showing posts with label TestKit. Show all posts
Showing posts with label TestKit. Show all posts

Sunday, October 26, 2014

Integration Testing using Akka.NET's TestKit

In Getting Started with Akka.NET and Handling messages and state with Akka.NET we created a calculator in Akka.NET that was able to add and subtract numbers and return the answer. It also stores the last answer and can respond with it when asked.

In Unit Testing using Akka.NET’s TestKit we created some unit tests to verify internal state of the actor.

In this post we’ll switch to integration tests – verifying we get correct messages back.

Code for this post: https://github.com/HCanber/akka.net-blog-examples/tree/master/04-calculator-testkit-integration

All posts in this series: Tutorials for Akka.NET

Note! This post was written using Akka.NET 0.7.0 and might not work for later versions

Unit Testing Recap

Unit Testing using Akka.NET’s TestKit we created some unit tests to verify internal state of the actor. We used ActorOfAsTestActorRef<T>() which creates the actor in the test’s ActorSystem (which is exposed thru the property Sys inside tests) and returns a TestActorRef<T> which give us access to the underlycing actor instance using the property UnderlyingActor.

[Fact]
public void Answer_should_initially_be_0()
{           
    TestActorRef<CalculatorActor> calculatorRef = ActorOfAsTestActorRef<CalculatorActor>("calculator");
    CalculatorActor calculator = calculatorRef.UnderlyingActor;
    Assert.Equal(0, calculator.Answer);
}

[Fact]
public void After_adding_1_and_1_Answer_should_be_2()
{
    TestActorRef<CalculatorActor> calculatorRef = ActorOfAsTestActorRef<CalculatorActor>("calculator");
    calculatorRef.Tell(new Add(1,1));
    CalculatorActor calculator = calculatorRef.UnderlyingActor;
    Assert.Equal(2, calculator.Answer);
}

Remember that everything is synchronous when writing these kind of tests. It’s the use of ActorOfAsTestActorRef<T>() that makes it synchronous. A CallingThreadDispatcher is used for actors created using ActorOfAsTestActorRef<T>() so when we send it a message using Tell(message) it’s not dispatched on another thread, but instead immediately processed before Tell returns control back to our test.

Integration tests

When writing integration tests, we create and run the actor the way we normally do. This means multi threaded under full concurrency (actors are shielded by the Actor model – the actor only processes on message at a time).

The first test: GetLastAnswer should initially respond with Answer(0)

In our first unit test we verfied that the internal state answer is 0 initially. We can also verify this by sending the actor a GetLastAnswer message and verify that we get an Answer(0) back.

The skeleton for the test looks like this:

public class CalculatorIntegrationTests : TestKit
{
    [Fact]
    public void Answer_should_initially_be_0()
    {
        var calculator = ActorOf<CalculatorActor>("calculator");
        calculator.Tell(GetLastAnswer.Instance);

        //Somehow verify we get an Anser(0) back            
    } 
}

So how can we verify that the calculator responds with what we expect? We could use Ask but there is a better way using TestKit.

TestActor

When the TestKit’s ActorSystem is created it also creates a special actor called TestActor. This instance is used as an implicit sender, so when we sent a message to calculator like this:

calculator.Tell(GetLastAnswer.Instance);

It was actually sent as if we’d specified TestActor as the sender:

calculator.Tell(GetLastAnswer.Instance, TestActor);

So when calculator send the response it will send it to TestActor which in turn will put the message in a queue that we can test against.

Created with Raphaël 2.1.0TestTestCalculatorCalculatorTestActorTestActorqueuequeueGetLastAnswer, Sender=TestActorAnswer(0)Enqueues Answer(0)

To test that the queue contains the correct message, or another way of seeing it: that TestActor received the correct message we use ExpectMessage<T>() and then assert that the value is correct.

[Fact]
public void Answer_should_initially_be_0()
{
    var calculator = ActorOf<CalculatorActor>("calculator");
    calculator.Tell(GetLastAnswer.Instance);

    var answer = ExpectMsg<Answer>();
    Assert.Equal(0, answer.Value);
}

The last two lines can also be written like this:

ExpectMsg<Answer>(a => a.Value == 0);

Isn’t it asynchronous?

We send a message to calculator which will process the message on another thread. At the same time we test that we have received a response. How can we be sure that the calculator has responded before we execute ExpectMessage<Answer>()? Don’t we need to synchronize somehow? Or is ir running synchronously as with unit tests?

No, it really is asynchronous, BUT ExpectMsg will wait up to 3 seconds before it fails.

Verifying Add

Rewriting the second unit test as a integration test is really easy now that we have all building blocks.

    [Fact]
    public void After_adding_1_and_1_Answer_should_be_2()
    {
        var calculator = ActorOf<CalculatorActor>("calculator");

        calculator.Tell(new Add(1, 1));
        var answer = ExpectMsg<Answer>();
        Assert.Equal(2, answer.Value);
    }

Be aware that the tests run in a full ActorSystem and everything is asynchronous even though it might look like synchronous code.

Code

Code on GitHub: https://github.com/HCanber/akka.net-blog-examples/tree/master/04-calculator-testkit-integration

All posts in this series: Tutorials for Akka.NET

Unit Testing using Akka.NET's TestKit

In Getting Started with Akka.NET and Handling messages and state with Akka.NET we created a calculator in Akka.NET that was able to add and subtract numbers and return the answer. It also stores the last answer and can respond with it when asked.

In this post we’ll introduce TestKit which will enable us to write unit and integration tests.

Code for this post: https://github.com/HCanber/akka.net-blog-examples/tree/master/03-calculator-testkit-unit

All posts in this series: Tutorials for Akka.NET

Note! This post was written using Akka.NET 0.7.0 and might not work for later versions

TestKit

TestKit is a module that allows us to write two types of tests:

  • Testing isolated pieces of code without involving the actor model, meaning without multiple threads; this implies completely deterministic behavior concerning the ordering of events and no concurrency concerns and will be called Unit Testing in the following.
  • Testing (multiple) encapsulated actors including multi-threaded scheduling; this implies non-deterministic order of events but shielding from concurrency concerns by the actor model and will be called Integration Testing in the following.

In Akka.NET TestKit is distributed in two nuget packages. First you need Akka.TestKit which contains all base functionality and then you need one targeted for a specific Test framework. At the time of writing, we have nuget packages for two frameworks: xUnit and VSTest/MSTest: Akka.TestKit.Xunit and Akka.TestKit.VsTest

Add a test project

We’ll continue with the code from Handling messages and state with Akka.NET which can be found on GitHub by adding a xUnit test project. The result can also be found on GitHub.

Start by adding a new Class Library project to the solution. We’ll call it Calculator.Tests. Delete Class1.cs from the project.

Add Akka.TestKit.XUnit to the project

Add the package Akka.TestKit.XUnit to the test project

Install-Package Akka.TestKit.Xunit

This will install all packages needed (Akka, Akka.TestKit, xunit).
Add a reference to the console app project.

Create the first test class

Create a new class, inherit from TestKit

using Akka.TestKit.Xunit;
using CalculatorApp;
using Xunit;

namespace Calculator.Tests
{
    public class CalculatorUnitTests : TestKit
    {
    }
}

Now we’re good to go!

TestKit’s test system

When writing tests using TestKit (by inheriting from TestKit) it creates an ActorSystem for us in which the tests are run, so you do not need to create one yourself.

The system can be accessed using Sys. This means that to create an actor in this system you’d do:

var calculator = Sys.ActorOf<CalculatorActor>("calculator");

Since this is done so frequently in tests you can skip the Sys property:

var calculator = ActorOf<CalculatorActor>("calculator");

Unit testing actors using TestActorRef

Unit testing actors is when we have full control over the order messages are processed, no concurrency and everything is synchronous. TestKit also provides a way to actually verify internal state of an actor.

Normally, when we create an actor like this we don’t get access to it’s internal state since the proxy ActorRef is returned:

ActorRef calculator = system.ActorOf<CalculatorActor>("calculator");

When using TestKit there is an overload that returns a TestActorRef<TActor> which gives as access to the underlying actor instance via the property UnderlyingActor.

The first test: Internal state answer should be 0 initially

Right after a calculator has been created it’s internal stored answer should be 0. To verify this is true, we need to make some changes to CalculatorActor so we can access the answer value. The local variable answer is turned into a private field, and we add an Answer property:

public class CalculatorActor : ReceiveActor
{
    private double _answer;

    public CalculatorActor()
    {
        Receive<Add>(add =>
        {
            _answer = add.Term1 + add.Term2;
            Sender.Tell(new Answer(_answer));
        });

        Receive<Subtract>(sub =>
        {
            _answer = sub.Term1 - sub.Term2;
            Sender.Tell(new Answer(_answer));
        });

        Receive<GetLastAnswer>(m => Sender.Tell(new Answer(_answer)));
    }

    public double Answer { get { return _answer; } }
}

Now we can write the test:

[Fact]
public void Answer_should_initially_be_0()
{           
    TestActorRef<CalculatorActor> calculatorRef = ActorOfAsTestActorRef<CalculatorActor>("calculator");
    CalculatorActor calculator = calculatorRef.UnderlyingActor;
    Assert.Equal(0, calculator.Answer);
}

Instead of ActorOf<CalculatorActor> we use ActorOfAsTestActorRef<CalculatorActor> which returns TestActorRef<CalculatorActor>. This type exposes the underlying actor in the UnderlyingActor property.
Once we got hold of it we verify that the Answer is 0.

If we run this test it passes.

Verifying that state is modified after handling messages

The CalculatorActor should always store the latest answer. So of we send it Add(1,1) the Answer property should be 2.

[Fact]
public void After_adding_1_and_1_Answer_should_be_2()
{
    TestActorRef<CalculatorActor> calculatorRef = ActorOfAsTestActorRef<CalculatorActor>("calculator");
    calculatorRef.Tell(new Add(1,1));
    CalculatorActor calculator = calculatorRef.UnderlyingActor;
    Assert.Equal(2, calculator.Answer);
}

Remember that everything is synchronous when writing these kind of tests. It’s the use of ActorOfAsTestActorRef<T>() that makes it synchronous. A CallingThreadDispatcher is used for actors created using ActorOfAsTestActorRef<T>() so when we send it a message using Tell(message) it’s not dispatch on another thread, but immediately processed before Tell returns control back to our test.

Code

Code on GitHub: https://github.com/HCanber/akka.net-blog-examples/tree/master/03-calculator-testkit-unit

All posts in this series: Tutorials for Akka.NET