我有一个演员,接收来自发起人的消息,然后询问工人,最后将结果发送给发起人。
代码中更明确:
public class MyActor extends UntypedActor {
private final ActorRef worker;
public MyActor(ActorRef worker) {
this.worker = worker;
}
@Override
public void onReceive(Object message) throws Exception {
if ("initiate".equals(message)) {
final ActorRef initiator = sender();
final Future f = Patterns.ask(worker, "ask:"+message, Timeout.apply(3, TimeUnit.SECONDS));
Patterns.pipe(f, context().system().dispatcher()).to(initiator);
}
}
}
现在尝试测试这个演员。
我需要测试什么(纠正我,如果我错了):
1)当"发起"收到,工人应该收到"问:启动"
2)当" responseFromWorker"接收,发起人应该收到" responseFromWorker"
并测试:
@Test
public void testIt() {
new JavaTestKit(system) {
{
JavaTestKit initiator = new JavaTestKit(system);
JavaTestKit worker = new JavaTestKit(system);
final Props props = Props.create(MyActor.class, worker.getRef());
final ActorRef subject = system.actorOf(props);
subject.tell("initiate", initiator.getRef());
worker.expectMsgEquals("ask:initiate");
subject.tell("responseFromWorker", worker.getRef());
//this fails
initiator.expectMsgEquals("responseFromWorker");
}
};
}
UPD
发起人没有收到消息:
java.lang.AssertionError: assertion failed: timeout (3 seconds) during expectMsg while waiting for responseFromWorker
虽然我的演员的代码是正确的:
static class Worker extends UntypedActor {
@Override
public void onReceive(Object message) throws Throwable {
if (message.equals("ask:initiate"))
sender().tell("responseFromWorker", self());
}
}
static class Initiator extends UntypedActor {
@Override
public void onReceive(Object message) throws Throwable {
if (message.equals("responseFromWorker"))
System.out.println("Initiator receive responseFromWorker");
}
}
@Test
public void noAkkaTestKit() {
final ActorRef worker = system.actorOf(Props.create(Worker.class));
final ActorRef initiator = system.actorOf(Props.create(Initiator.class));
final ActorRef subject = system.actorOf(Props.create(MyActor.class, worker));
subject.tell("initiate", initiator);
}
所以我做错了什么。如何使用JavaTestKit
正确测试?
答案 0 :(得分:3)
因为要求将来的模式会创建一个新的actor来接收响应msg,所以代码
subject.tell("responseFromWorker", worker.getRef());
会将讯息直接发送给主题,而不是发送给该演员。
您可以将msg发送到测试探针的最后一个msg发件人
我写了一个scala版本
import java.util.concurrent.TimeUnit
import akka.actor.{Props, Actor, ActorRef, ActorSystem}
import akka.pattern.{ask, pipe}
import akka.testkit.{TestProbe, ImplicitSender, TestKit}
import org.scalatest.{BeforeAndAfterAll, BeforeAndAfterEach, Matchers, WordSpecLike}
class MyActor(worker: ActorRef) extends Actor {
import context.dispatcher
override def receive: Receive = {
case message@"initiate" =>
val initiator = sender()
println("received " + message)
val f = ask(worker, "ask:" + message)(akka.util.Timeout(3, TimeUnit.SECONDS))
f pipeTo initiator
case msg =>
println(msg)
}
}
class ActorSpec extends TestKit(ActorSystem("MySpec"))
with ImplicitSender with WordSpecLike with BeforeAndAfterAll with BeforeAndAfterEach with Matchers {
val workerProbe = TestProbe()
val initiatorProbe = TestProbe()
val props = Props(new MyActor(workerProbe.ref))
val subject = system.actorOf(props)
subject.tell("initiate", initiatorProbe.ref)
workerProbe.expectMsg("ask:initiate")
workerProbe.sender.tell("responseFromWorker", workerProbe.ref)
initiatorProbe.expectMsg("responseFromWorker")
}