如何使用 TestKit 不处理发送给自己的消息
How to use TestKit to not process messages sent to Self
我正在尝试测试 Actor。在一种情况下,我想关注它如何处理消息。出于各种设计原因,我想将一个动作拆分为同一演员的 2 个独立的不同步骤/消息。主要是,第二阶段(即第二条消息)可能无法处理,可能需要重新安排。所以对于我的单元测试,我想关注第 1 阶段的行为,但是使用 Test Kit 它会自动处理消息,因为我称之为 this.Self.Tell("2");
.
我简化了代码并将其放在这里。以下是演员代码:
public class TestSelfActor : UntypedActor
{
protected override void OnReceive(object message)
{
switch (message)
{
case string s:
if (s == "1")
{
Console.WriteLine("one");
this.Self.Tell("2");
this.Sender.Tell("test");
}
else if (s == "2") { Console.WriteLine("two"); }
break;
}
}
}
这里是测试方法
public void TestSendingMessage()
{
target = Sys.ActorOf(Props.Create(() => new TestSelfActor()));
target.Tell("1");
actual = this.ExpectMsg<string>();
Assert.AreEqual("test", actual);
}
如果我运行这个,它会通过,输出会显示
one
two
理想情况下,有一些方法可以设置测试,这样我就可以向它发送第一条消息,然后 然后 断言它告诉自己消息“2”,而不是每次输出到控制台“2”。
一些额外的信息,我正在 运行ning .NET Framework 4.8 和 akka/akka.testkit 1.3.8,虽然我认为代码和问题足够简单,但它并不版本有关系吗?
在您的测试项目中,您可以继承自 TestSelfActor 并覆盖 AroundReceive 方法(然后您可以使用 NSubstitute、Moq 等来伪造它),
在 AroundReceive 中,您可以拦截消息并决定如何处理它们(例如,return false for "2" in your case)
下面是使用 XUnit 和 NSubstitute 的例子。我还可以扩展它并在 XUnit fixture 中创建伪造的 MessageHandler 以使其可重用。如果你想测试默认行为,你总是可以传递 null 。
希望这有帮助
using Akka.Actor;
using Akka.TestKit.Xunit;
using NSubstitute;
using System;
using Xunit;
namespace ActorTests
{
public class TestSelfActor : UntypedActor
{
protected override void OnReceive(object message)
{
switch (message)
{
case string s:
if (s == "1")
{
Console.WriteLine("one");
this.Self.Tell("2");
this.Sender.Tell("test");
}
else if (s == "2") { Console.WriteLine("two"); }
break;
}
}
}
public interface IMessageHandler
{
Func<object, bool> AroundReceiveHandler { get; }
}
public class FakeActor : TestSelfActor
{
private readonly IMessageHandler _messageHandler;
public FakeActor(IMessageHandler messageHandler)
{
_messageHandler = messageHandler;
}
protected override bool AroundReceive(Receive receive, object message)
{
var acceptMessage = _messageHandler?.AroundReceiveHandler?.Invoke(message) ?? true;
return acceptMessage && base.AroundReceive(receive, message);
}
}
public class SelfActorSpecs : TestKit
{
[Fact]
public void When_Sender_TellsOne_Actor_Should_RespondWith_Test_NotSending_Two_ToSelf()
{
var messageHandler = Substitute.For<IMessageHandler>();
messageHandler.AroundReceiveHandler(Arg.Any<string>()).Returns(true);
messageHandler.AroundReceiveHandler("2").Returns(false);
var target = Sys.ActorOf(Props.Create(() => new FakeActor(messageHandler)));
target.Tell("1");
ExpectMsg<string>(x => x == "test");
}
}
}
我正在尝试测试 Actor。在一种情况下,我想关注它如何处理消息。出于各种设计原因,我想将一个动作拆分为同一演员的 2 个独立的不同步骤/消息。主要是,第二阶段(即第二条消息)可能无法处理,可能需要重新安排。所以对于我的单元测试,我想关注第 1 阶段的行为,但是使用 Test Kit 它会自动处理消息,因为我称之为 this.Self.Tell("2");
.
我简化了代码并将其放在这里。以下是演员代码:
public class TestSelfActor : UntypedActor
{
protected override void OnReceive(object message)
{
switch (message)
{
case string s:
if (s == "1")
{
Console.WriteLine("one");
this.Self.Tell("2");
this.Sender.Tell("test");
}
else if (s == "2") { Console.WriteLine("two"); }
break;
}
}
}
这里是测试方法
public void TestSendingMessage()
{
target = Sys.ActorOf(Props.Create(() => new TestSelfActor()));
target.Tell("1");
actual = this.ExpectMsg<string>();
Assert.AreEqual("test", actual);
}
如果我运行这个,它会通过,输出会显示
one
two
理想情况下,有一些方法可以设置测试,这样我就可以向它发送第一条消息,然后 然后 断言它告诉自己消息“2”,而不是每次输出到控制台“2”。
一些额外的信息,我正在 运行ning .NET Framework 4.8 和 akka/akka.testkit 1.3.8,虽然我认为代码和问题足够简单,但它并不版本有关系吗?
在您的测试项目中,您可以继承自 TestSelfActor 并覆盖 AroundReceive 方法(然后您可以使用 NSubstitute、Moq 等来伪造它), 在 AroundReceive 中,您可以拦截消息并决定如何处理它们(例如,return false for "2" in your case) 下面是使用 XUnit 和 NSubstitute 的例子。我还可以扩展它并在 XUnit fixture 中创建伪造的 MessageHandler 以使其可重用。如果你想测试默认行为,你总是可以传递 null 。 希望这有帮助
using Akka.Actor;
using Akka.TestKit.Xunit;
using NSubstitute;
using System;
using Xunit;
namespace ActorTests
{
public class TestSelfActor : UntypedActor
{
protected override void OnReceive(object message)
{
switch (message)
{
case string s:
if (s == "1")
{
Console.WriteLine("one");
this.Self.Tell("2");
this.Sender.Tell("test");
}
else if (s == "2") { Console.WriteLine("two"); }
break;
}
}
}
public interface IMessageHandler
{
Func<object, bool> AroundReceiveHandler { get; }
}
public class FakeActor : TestSelfActor
{
private readonly IMessageHandler _messageHandler;
public FakeActor(IMessageHandler messageHandler)
{
_messageHandler = messageHandler;
}
protected override bool AroundReceive(Receive receive, object message)
{
var acceptMessage = _messageHandler?.AroundReceiveHandler?.Invoke(message) ?? true;
return acceptMessage && base.AroundReceive(receive, message);
}
}
public class SelfActorSpecs : TestKit
{
[Fact]
public void When_Sender_TellsOne_Actor_Should_RespondWith_Test_NotSending_Two_ToSelf()
{
var messageHandler = Substitute.For<IMessageHandler>();
messageHandler.AroundReceiveHandler(Arg.Any<string>()).Returns(true);
messageHandler.AroundReceiveHandler("2").Returns(false);
var target = Sys.ActorOf(Props.Create(() => new FakeActor(messageHandler)));
target.Tell("1");
ExpectMsg<string>(x => x == "test");
}
}
}