如何使用模式管道测试actor

时间:2016-12-07 06:15:49

标签: akka

我有一个演员,接收来自发起人的消息,然后询问工人,最后将结果发送给发起人。

代码中更明确:

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正确测试?

1 个答案:

答案 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")
}