1

I have a problem in some unit tests of a ReceivePersistentActor implementation using PersistAll and PersistAllAsync methods.

The problem is that when unit testing with TestKit.NUnit, the PersistAll/Async calls never call their completion callbacks. Persist/Async calls work fine however and the PersistAll/Async calls work fine outside of unit testing.

Has this something to do with TestKit and the way it tries to run things on the CallingThreadDispatcher?

I'm not sure how to write unit tests for code where PersistAll/Async is used - the tests always fail by timing out due to the callbacks never being invoked (where I have my Sender.Tell code).

I'm not doing anything weird - i'm using the in-memory journal and snapshot-store and these are running on the default dispatcher (I tried using calling-thread dispatcher for these but then nothing worked at all in the unit tests).

public interface IEvent;
public class Test : ReceivePersistentActor {

    public class StringReceivedEvent:IEvent {}

    public Test()
    {
        Console.WriteLine("Started"); // <-- This is seen, but the next console output is not - callback is never fired
        Command<string>(message => { 
            Console.WriteLine($"Received {message}");

            PersistAll(new List<IEvent>(){new StringReceivedEvent()}, @event => {
                Console.WriteLine("Persisted event"); //<-- never see this
                Sender.Tell(true); //<-- this never gets called
            });
        });
    }

    public override string PersistenceId => "test-id";
}

[TestFixture]
public class Tests : Akka.TestKit.NUnit.TestKit
{
    IActorRef subject;

    public PublishingTests() : base(ConfigurationFactory.Load().WithFallback(Akka.TestKit.Configs.TestConfigs.DefaultConfig))
    {
    }

    [SetUp]
    public void Setup() {
        subject = ActorOf(Props.Create<Test>(), "My-Test-Actor");
    }

    [Test]
    public void Can_Persist_Event_And_Send_Completion_Reply() {

        subject.Tell("hello");
        ExpectMsg<bool>(TimeSpan.FromSeconds(15)); //<---- This times out

    }
}
AndyMoose
  • 425
  • 3
  • 11
  • The question in its current state is incomplete and therefore unclear. Read [ask] and then [edit] the question to provide a [mcve] that can be used to reproduce the problem, allowing a better understanding of what is being asked. – Nkosi Apr 08 '18 at 23:54

1 Answers1

1

I just tried your code in a new .NET Core 2.0 project (with some slight modifications to get it to compile), and it works fine.

Here is the complete replication steps. First on commandline/PowerShell:

mkdir akka-net-persistence-unit-testing-issue-so
cd akka-net-persistence-unit-testing-issue-so
# Install nunit template if not already done:
dotnet new -i NUnit3.DotNetNew.Template
dotnet new nunit -n TestProject
cd TestProject
dotnet add package Akka
dotnet add package Akka.Persistence
dotnet add package Akka.TestKit.Nunit

I now have a .csproj file that looks like this:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>

    <IsPackable>false</IsPackable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Akka" Version="1.3.7" />
    <PackageReference Include="Akka.Persistence" Version="1.3.7" />
    <PackageReference Include="Akka.TestKit.NUnit" Version="1.3.2" />
    <PackageReference Include="nunit" Version="3.10.1" />
    <PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.1" />
  </ItemGroup>

</Project>

Then, for the sake of just reproducing, I put all code in one file like this:

using System;
using System.Collections.Generic;
using Akka.Actor;
using Akka.Configuration;
using Akka.Persistence;
using NUnit.Framework;

namespace TestProject
{
    public interface IEvent {};

    public class TestActor : ReceivePersistentActor
    {

        public class StringReceivedEvent : IEvent { }

        public TestActor()
        {
            Console.WriteLine("Started");
            Command<string>(message =>
            {
                Console.WriteLine($"Received {message}");

                PersistAll(new List<IEvent>() { new StringReceivedEvent() }, @event =>
                {
                    Console.WriteLine("Persisted event");
                    Sender.Tell(true); //<-- this is apparently getting called now!
                });
            });
        }

        public override string PersistenceId => "test-id";
    }

    [TestFixture]
    public class PublishingTests : Akka.TestKit.NUnit.TestKit
    {
        IActorRef subject;

        public PublishingTests() : base(ConfigurationFactory.Load().WithFallback(Akka.TestKit.Configs.TestConfigs.DefaultConfig))
        {
        }

        [SetUp]
        public void Setup()
        {
            subject = ActorOf(Props.Create<TestActor>(), "My-Test-Actor");
        }

        [Test]
        public void Can_Persist_Event_And_Send_Completion_Reply()
        {

            subject.Tell("hello");
            ExpectMsg<bool>(TimeSpan.FromSeconds(15)); //<---- This no longer times out :-)
        }
    }
}

Then you should be able to test your code from command line again:

dotnet test

Giving output:

Build started, please wait...
Build completed.

Test run for C:\Source\Privat\SoTest\akka-net-persistence-unit-testing-issue-so\TestProject\bin\Debug\netcoreapp2.0\Test
Project.dll(.NETCoreApp,Version=v2.0)
Microsoft (R) Test Execution Command Line Tool Version 15.7.0-preview-20180320-02
Copyright (c) Microsoft Corporation.  All rights reserved.

Starting test execution, please wait...

Total tests: 1. Passed: 1. Failed: 0. Skipped: 0.
Test Run Successful.
Test execution time: 2,8449 Seconds

I had a similar problem with the UntypedPersistentActor and xUnit, but it suddenly disappeared after I changed it to a ReceivePersistentActor, and restarted Visual Studio, and other things, but there were too many things going on at once, so unfortunately I am not able to provide you with a good answer to exactly what I did to solve it (also the reason which I wanted to try to figure this out and reproduce it here, but I wasn't able to). I hope a set of complete reproduction steps with exact package versions for a working project helps you out instead...

audunsol
  • 398
  • 3
  • 9
  • Thanks for trying. I meant to update this question earlier, I infact managed to fix the problem by modifying the config for the inmemory journal and snapshot store. I really don’t know quite what the problem was but eventually it worked. I also saw somewhere that running visual studio as administrator also makes a difference with akka.net testing. – AndyMoose May 19 '18 at 19:39