[英]How to use TestKit in Akka.NET
我正在嘗試測試我的Akka.NET演員,但是在使用TestKit時遇到了一些問題,並了解它是如何工作的。
由於Akka.NET中沒有關於單元測試的官方文檔,我已經探索了Akka.NET repo的示例代碼,但是那里使用的示例對我不起作用。
我用於參考的測試是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測試,創建一個actor
var system = ActorSystem.Create("test");
var actor = system.ActorOf<BecomeActor>("become");
並且發送和斷言消息
actor.Tell(message, TestActor);
ExpectMsg(message);
但是,當我嘗試使用這種方法來實例化一個actor,以及許多其他基於TestKit方法的方法(見下文)時,我一直得到samme失敗的測試錯誤:
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線移到actor.Tell線上方(因為在你采取行動之前對Expect做了更有意義的事情,而不是在之后驗證期望),但這也會導致Timeout錯誤。
我試過NUnit和XUnit TestKits。
我可能忽略了一些非常基本的東西。
TestKit用於更多行為測試,以驗證您的演員是否在整個演員系統的上下文中按預期工作。 這更像是黑盒測試 - 你沒有直接到達演員的內部。 相反,最好關注諸如給定信號A和演員行為B之類的行為,它應該將消息C發送給另一個演員D.
在你的示例中, Greeter
actor的問題是它是靜音 - 雖然它可以接收一些輸入,但它不會在結果中做任何事情。 從整個系統的角度來看,它可能已經死了,沒人會關心。
使用其他示例 - 給出以下actor:
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");
}
}
如您所見,這里我不檢查actor的內部狀態。 相反,我正在觀察它對我發送給它的信號的反應,並驗證它是否是預期的結果。
您沒有也不應該創建自己的ActorSystem
作為任何Akka.TestKit測試的一部分。 您可以在任何測試中使用內置的Sys
屬性,並且您將可以訪問TestKit
本身使用的相同ActorSystem
。
所以你應該做這樣的事情:
var actor = Sys.ActorOf<BecomeActor>("become");
之所以這很重要 :除非你使用的是Akka.Remote,否則將TestActor
和您的BecomeActor
放在同一個ActorSystem
是必要的,以便它們相互發送消息。 否則, TestActor
無法接收任何消息,您的ExpectMsg
調用將超時。
編輯:整個測試演員系統現在在單元測試之間被拆除。
編輯2:請參閱我們寫入Akka.NET TestKit的詳細指南,以獲得更長的解釋 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.