sender() 导致执行死信,但不会导致单元测试
sender() results in deadLetters for implementation but not in unit tests
我正在使用 Akka 经典演员(运行在 Play 框架中)并且运行遇到 sender()
方法的问题。当我构建 运行 代码(使用 sbt run
)时,我可以看到 sender()
解析为 deadLetters
actor。但是,当 运行ning 对该 actor 进行单元测试时,sender()
解析为正确的 ActorRef(即使它不应该)。
sender()
正在不久的将来被调用,这就是为什么我在 运行 实际实施时看到 deadLetters
。但是,出于某种原因,我在单元测试中没有看到 deadLetters
。关于为什么单元测试和 运行ning 实例之间存在行为差异的任何想法?
一些示例代码以了解代码结构
class MyActor extends Actor {
private def throwError() = {
// THIS IS WHERE sender() BEHAVIOR DIFFERENTIATES BETWEEN IMPLEMENTATION AND UNITTESTS
sender() ! MyErrorMessage()
throw new Exception()
}
private def myFutureMethod(args: SomeType): Future[Done] = {
for {
Some logic here...
} yield {
if (some logic check...)
throwError()
else
Done
}
}
override def stepReceive = {
case MyMessage(args) =>
myFutureMethod(args)
}
}
一些示例代码来了解单元测试结构
"My failure test case" in {
val testProbe = TestProbe()
myActorImpl.tell(MyMessage(args), testProbe)
// testProbe SHOULD BE NOT BE RECEIVING A MESSAGE BASED ON THE ABOVE
// IMPLEMENTATION, BUT IT DOES.
testProbe.expectNoMessage()
}
如果有人有一些调试技巧或想法,那就太好了。谢谢。
在演员中作为 Future
的一部分执行的代码中调用 sender
是不确定的(即竞争条件),因为您的 MyActor
可以继续处理另一个Future
中的代码执行之前的消息,如果从那时起,sender
将发生变化,可能会变为 deadLetters
.
在您的测试中,如果 myActorImpl
尚未处理消息,sender
仍将指向测试探针。
假设您希望消息真正发送给发件人,您需要在将其传递给 Future
之前捕获它,按照这些行
class MyActor extends Actor {
private def throwError(target: ActorRef) = {
// uses the captured sender, no race condition
target ! MyErrorMessage()
throw new Exception()
}
private def myFutureMethod(args: SomeType, sender: ActorRef): Future[Done] = {
for {
Some logic here...
} yield {
if (some logic check...)
throwError(sender)
else
Done
}
}
override def stepReceive = {
case MyMessage(args) =>
myFutureMethod(args, sender) // captures the sender reference
}
}
我正在使用 Akka 经典演员(运行在 Play 框架中)并且运行遇到 sender()
方法的问题。当我构建 运行 代码(使用 sbt run
)时,我可以看到 sender()
解析为 deadLetters
actor。但是,当 运行ning 对该 actor 进行单元测试时,sender()
解析为正确的 ActorRef(即使它不应该)。
sender()
正在不久的将来被调用,这就是为什么我在 运行 实际实施时看到 deadLetters
。但是,出于某种原因,我在单元测试中没有看到 deadLetters
。关于为什么单元测试和 运行ning 实例之间存在行为差异的任何想法?
一些示例代码以了解代码结构
class MyActor extends Actor {
private def throwError() = {
// THIS IS WHERE sender() BEHAVIOR DIFFERENTIATES BETWEEN IMPLEMENTATION AND UNITTESTS
sender() ! MyErrorMessage()
throw new Exception()
}
private def myFutureMethod(args: SomeType): Future[Done] = {
for {
Some logic here...
} yield {
if (some logic check...)
throwError()
else
Done
}
}
override def stepReceive = {
case MyMessage(args) =>
myFutureMethod(args)
}
}
一些示例代码来了解单元测试结构
"My failure test case" in {
val testProbe = TestProbe()
myActorImpl.tell(MyMessage(args), testProbe)
// testProbe SHOULD BE NOT BE RECEIVING A MESSAGE BASED ON THE ABOVE
// IMPLEMENTATION, BUT IT DOES.
testProbe.expectNoMessage()
}
如果有人有一些调试技巧或想法,那就太好了。谢谢。
在演员中作为 Future
的一部分执行的代码中调用 sender
是不确定的(即竞争条件),因为您的 MyActor
可以继续处理另一个Future
中的代码执行之前的消息,如果从那时起,sender
将发生变化,可能会变为 deadLetters
.
在您的测试中,如果 myActorImpl
尚未处理消息,sender
仍将指向测试探针。
假设您希望消息真正发送给发件人,您需要在将其传递给 Future
之前捕获它,按照这些行
class MyActor extends Actor {
private def throwError(target: ActorRef) = {
// uses the captured sender, no race condition
target ! MyErrorMessage()
throw new Exception()
}
private def myFutureMethod(args: SomeType, sender: ActorRef): Future[Done] = {
for {
Some logic here...
} yield {
if (some logic check...)
throwError(sender)
else
Done
}
}
override def stepReceive = {
case MyMessage(args) =>
myFutureMethod(args, sender) // captures the sender reference
}
}