Как использовать TestKit в Akka.NET
Я пытаюсь проверить мой Akka.NET актеры, но у них есть некоторые проблемы с TestKit и понимание того, как он работает.
так как нет официальной документации для модульного тестирования в Akka.NET тем не менее, я исследовал Akka.NET РЕПО, например, код, но примеры, используемые там, не работают для меня.
тесты, которые я использовал для справки, это ReceiveActorTests.cs и ReceiveActorTests_Become.cs, так как они близки к сценарий, который я пытаюсь протестировать в своем приложении.
вот какой-то фиктивный код:
учитывая этого актера
public class Greeter : ReceiveActor
{
    public Greeter()
    {
        NotGreeted();
    }
    private void NotGreeted()
    {
        Receive<Greeting>(msg => Handle(msg));
    }
    private void Greeted()
    {
        Receive<Farewell>(msg => Handle(msg));
    }
    private void Handle(Greeting msg)
    {
        if (msg.Message == "hello")
        {
            Become(Greeted);
        }
    }
    private void Handle(Farewell msg)
    {
        if (msg.Message == "bye bye")
        {
            Become(NotGreeted);
        }
    }
}
Я хочу проверить, что он получает приветствие и прощальные сообщения правильно, и правильно входит в состояния становления. Глядя на ReceiveActorTests_Become.cs тесты, актер создается
var system = ActorSystem.Create("test");
var actor = system.ActorOf<BecomeActor>("become");
и сообщение отправляется и утверждается
actor.Tell(message, TestActor);
ExpectMsg(message);
однако, когда я пытаюсь использовать этот подход для создания экземпляра актер и многие другие, основанные на методах TestKit (см. Ниже), я продолжаю получать ошибку samme failed test:
Xunit.Sdk.TrueExceptionFailed: Timeout 00:00:03 while waiting for a message of type ConsoleApplication1.Greeting 
Expected: True
Actual:   False
Это мой тест:
public class XUnit_GreeterTests : TestKit
{
    [Fact]
    public void BecomesGreeted()
    {
        //var system = ActorSystem.Create("test-system"); // Timeout error
        //var actor = system.ActorOf<Greeter>("greeter"); // Timeout error
        //var actor = ActorOfAsTestActorRef<Greeter>("greeter"); // Timeout error
        //var actor = ActorOf(() => new Greeter(), "greeter"); // Timeout error
        //var actor = Sys.ActorOf<Greeter>("greeter"); // Timeout error
        //var actor = Sys.ActorOf(Props.Create<Greeter>(), "greeter"); // Timeout error
        var actor = CreateTestActor("greeter"); // Works, but doesn't test my Greeter actor, but rather creates a generic TestActor (as I understand it)
        var message = new Greeting("hello");
        actor.Tell(message, TestActor);
        ExpectMsg(message);
    }
}
Я также попытался переместить строку ExpectMsg выше актера.Tell line (так как было более разумно ожидать чего-то, прежде чем действовать на нем, и скорее проверить ожидание после), но это также приводит к ошибке тайм-аута.
Я пробовал с Тесткитами NUnit и XUnit.
вероятно, что-то очень простое, что я пропустил.
2 ответов
TestKit используется для более поведенческого тестирования, чтобы проверить, работают ли ваши актеры так, как ожидалось, в контексте всей системы актеров. Это больше похоже на тестирование "черного ящика" - вы не достигнете нутро актера напрямую. Вместо этого лучше сосредоточиться на поведении, таком как учитывая сигнал A и поведение актера B, он должен излучать сообщение C другому актору D.
в вашем примере проблема с Greeter актер заключается в том, что он немой-хотя он может получать некоторые входы, он не ничего в результате. С точки зрения всей системы, она может быть мертва, и никому нет до нее дела.
используя другой пример-данный следующий актер:
public class Greeter : ReceiveActor
{
    public Greeter()
    {
        Receive<Greet>(greet =>
        {
            // when message arrives, we publish it on the event stream 
            // and send response back to sender
            Context.System.EventStream.Publish(greet.Who + " sends greetings");
            Sender.Tell(new GreetBack(Self.Path.Name));
        });
    }
}
давайте создадим пример тестовой спецификации:
public class GreeterSpec : TestKit
{
    private IActorRef greeter;
    public GreeterSpec() : base()
    {
        greeter = Sys.ActorOf<Greeter>("TestGreeter");
    }
    [Fact]
    public void Greeter_should_GreetBack_when_Greeted()
    {
        // set test actor as message sender
        greeter.Tell(new Greet("John Snow"), TestActor);
        // ExpectMsg tracks messages received by TestActors
        ExpectMsg<GreetBack>(msg => msg.Who == "TestGreeter");
    }
    [Fact]
    public void Greeter_should_broadcast_incoming_greetings()
    {
        // create test probe and subscribe it to the event bus
        var subscriber = CreateTestProbe();
        Sys.EventStream.Subscribe(subscriber.Ref, typeof (string));
        greeter.Tell(new Greet("John Snow"), TestActor);
        // check if subscriber received a message
        subscriber.ExpectMsg<string>("John Snow sends greetings");
    }
}
как видите, здесь я не проверяю внутреннее состояние актера. Вместо этого я наблюдаю, как он реагирует на сигналы, которые я посылаю ему, и проверяю, является ли это ожидаемым результатом.
вы не и не должны создавать свои собственные ActorSystem как часть любой Акка.TestKit тест. Вы можете использовать встроенный Sys свойство в любом из ваших тестов, и вы получите доступ к тому же ActorSystem используется .
Итак, вы должны сделать что-то вроде этого:
var actor = Sys.ActorOf<BecomeActor>("become");
причина, почему это важно: С TestActor и свой BecomeActor в том же ActorSystem необходимо для того, чтобы отправлять сообщения друг другие, если вы не используете Akka.Дистанционный. В противном случае TestActor не удается получить никаких сообщений и ваш ExpectMsg вызовы времени.
EDIT: вся система тестового актера теперь разрывается между модульными тестами.
EDIT 2: см.подробное руководство мы написали Akka.NET TestKit для более длинного объяснения.