让我们说我有一个自己创作演员的父演员。
public static class Parent extends UntypedActor {
private ActorRef child = context().actorOf(Props.create(Child.class));
@Override
public void onReceive(Object message) throws Exception {
// do some stuff
child.tell("some stuff", self());
}
}
public static class Child extends UntypedActor {
@Override
public void onReceive(Object message) throws Exception {
}
}
我怎么能模仿这个孩子的演员?谷歌没有给我任何合理的结果。 Akka的文档告诉我,创建演员是一种很好的做法。但是,如果我甚至不能测试我的演员,我怎么能遵循这种做法呢?
答案 0 :(得分:1)
我使用这个答案中描述的类似问题的探针:
How to mock child Actors for testing an Akka system?
ActorSystem system = ActorSystem.create();
new JavaTestKit( system )
{{
final JavaTestKit probe = new JavaTestKit( system );
final Props props = Props.create( SupervisorActor.class );
final TestActorRef<SupervisorActor> supervisorActor =
TestActorRef.create( system, props, "Superman" );
supervisorActor.tell( callCommand, getTestActor() );
probe.expectMsgEquals(42);
assertEquals(getRef(), probe.getLastSender());
}};
答案 1 :(得分:0)
以下代码将用Scala编写,但我想这同样适用于Java。答案是您可以使用TestProbe来模拟您的孩子演员。我们来看这个例子:
import akka.actor.{Actor, Props}
class Parent extends Actor {
import Parent._
val child = context.actorOf(Child.props)
override def receive: Receive = {
case TellName(name) => child ! name
case Reply(msg) => sender() ! msg
}
}
object Parent {
case class TellName(name: String)
case class Reply(text: String)
def props = Props(new Parent)
}
class Child extends Actor {
override def receive: Actor.Receive = {
case name: String => sender ! Parent.Reply(s"Hi there $name")
}
}
object Child {
def props = Props(new Child)
}
因此,我们有一个Parent
actor,它向TellName
actor发送消息Child
。收到消息Child
之后,演员将通过向其发件人发送包含内容的Reply
消息进行回复 - 即“你好乔”。现在,这是一个测试:
class ParentSpec extends TestKit(ActorSystem("test")) with WordSpecLike with Matchers with ImplicitSender {
val childProbe = TestProbe()
"Parent actor" should {
"send a message to child actor" in {
childProbe.setAutoPilot(new AutoPilot {
override def run(sender: ActorRef, msg: Any): AutoPilot = msg match {
case name: String => sender ! Reply(s"Hey there $name")
NoAutoPilot
}
})
val parent = system.actorOf(Props(new Parent {
override val child = childProbe.ref
}))
parent ! TellName("Johnny")
childProbe.expectMsg("Johnny") // Message received by a test probe
expectMsg("Hey there Johnny") // Reply message
}
}
}
现在,为了模拟我们的Child
actor的行为,我们可以使用setAutoPilot
方法来定义在收到特定类型的消息后它将如何回复。在我们的例子中,假设Child
actor收到字符串类型的消息“Jonny”,它将回复一条内容为“Hey there Johnny”的Reply
消息。
首先,我们发送TellName
内容为“Johnny”。然后我们可以断言我们的模拟演员收到的消息 - childProbe.expectMsg("Johnny")
。之后我们可以断言回复消息 - expectMsg("Hey there Johnny")
。请注意,回复消息将是“Hey there Johnny”而不是“Hi there Johnny”,它对应于我们在模拟的Child
actor中定义的改变行为。
答案 2 :(得分:0)
可以使用several approaches来嘲笑儿童演员。其中之一是外部化从父演员创建孩子的代码。
要做到这一点,您需要重写您的父级演员,并向其传递一个可以创建您的子级演员的函数:
注意:由于deprecation in version 2.5.0,我们将使用AbstractActor
代替UntypedActor
。
public class Parent extends AbstractActor {
private final ActorRef child;
public Parent(Function<ActorRefFactory, ActorRef> childCreator) {
this.child = childCreator.apply(getContext());
}
public static Props props(Function<ActorRefFactory, ActorRef> childCreator) {
return Props.create(Parent.class, childCreator);
}
@Override
public Receive createReceive() {
return receiveBuilder()
.matchEquals("send ping", s -> child.tell("ping", getSelf()))
.match(String.class, System.out::println)
.build();
}
}
您的儿童演员将保持不变:
public class Child extends AbstractActor {
@Override
public Receive createReceive() {
return receiveBuilder()
.matchEquals("ping", s -> getSender().tell("pong", getSelf()))
.build();
}
}
现在,在测试中,您可以使用探测参与者引用来测试应发送给Child
参与者的消息,即probe
将充当Child
参与者模拟:
public class ParentTest {
static ActorSystem system;
@BeforeClass
public static void setUpClass() {
system = ActorSystem.create();
}
@AfterClass
public static void tearDownClass() {
TestKit.shutdownActorSystem(system);
system = null;
}
@Test
public void givenParent_whenSendPing_thenPingChild() {
TestKit probe = new TestKit(system);
Function<ActorRefFactory, ActorRef> childCreator = arf -> probe.getRef();
ActorRef parentActor = system.actorOf(Parent.props(childCreator));
probe.send(parentActor, "send ping");
probe.expectMsgEquals("ping");
}
}
因此,代替使用(将在实际的应用程序代码中使用):
Function<ActorRefFactory, ActorRef> childCreator = arf -> arf
.actorOf(Props.create(Child.class));
我们将使用:
Function<ActorRefFactory, ActorRef> childCreator = arf -> probe.getRef();
并检查probe
是否收到“ ping”消息。
希望有帮助。有关给定方法的更多信息,请参见here。