TestKit.expectMsgClass 作为

TestKit.expectMsgClass in Akka

在下面的代码中:

TestKit probe = new TestKit(system); // line 1
ActorRef deviceActor = system.actorOf(Device.props("group", "device")); // line 2

deviceActor.tell(new DeviceManager.RequestTrackDevice("group", "device"), probe.getRef()); // line 3
probe.expectMsgClass(DeviceManager.DeviceRegistered.class); // line 4
assertEquals(deviceActor, probe.getLastSender()); // line 5

如果我注释掉第 4 行,则测试失败。第 3 行足以将消息发送给演员。那么第 4 行到底在做什么?

要了解发生了什么,让我们检查一下源代码。

这里是getLastSender()的定义,其中p是一个TestProbe:

public ActorRef getLastSender() {
  return p.lastMessage().sender();
}

lastMessageTestKit.scala中声明如下:

private[akka] var lastMessage: Message = NullMessage

lastMessage 变量在 receiveWhilereceiveOne 两种方法之一中发生变异。 expectMsgClass方法调用后者:

def expectMsgClass[C](max: FiniteDuration, c: Class[C]): C = expectMsgClass_internal(max.dilated, c)

private def expectMsgClass_internal[C](max: FiniteDuration, c: Class[C]): C = {
  val o = receiveOne(max)
  // ...
}

基本上,如果您不在测试中调用 TestKit 的 built-in 断言之一(例如,expectMsg* 方法之一),那么 lastMessage 将保持不变为 NullMessage。如果 lastMessageNullMessage,那么调用 lastMessage.sender 将导致异常,并且您的测试中的 assertEquals(deviceActor, probe.getLastSender()); 将失败。

另一方面,如果您确实调用了 built-in 断言,例如 expectMsgClass,那么 lastMessage 将被适当地设置,并且 lastMessage 的发送者将正确解析。

简而言之,调用 getLastSender() 假定使用 TestKit 断言。这隐含在 documentation(强调我的):

The probe stores the sender of the last dequeued message (i.e. after its expectMsg* reception), which may be retrieved using the getLastSender() method.