Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 发送到“TestProbe”的测试消息是否可能在“TestActor.SetAutoPilot(pilot)”之前到达`_Scala_Akka_Akka Testkit - Fatal编程技术网

Scala 发送到“TestProbe”的测试消息是否可能在“TestActor.SetAutoPilot(pilot)”之前到达`

Scala 发送到“TestProbe”的测试消息是否可能在“TestActor.SetAutoPilot(pilot)”之前到达`,scala,akka,akka-testkit,Scala,Akka,Akka Testkit,示例表明,我们可以在调用setAutoPilot后立即向TestProbe发送消息: probe.setAutoPilot(new TestActor.AutoPilot { def run(sender: ActorRef, msg: Any): TestActor.AutoPilot = msg match { case "stop" ⇒ TestActor.NoAutoPilot case x ⇒ testActor.tel

示例表明,我们可以在调用
setAutoPilot
后立即向
TestProbe
发送消息:

  probe.setAutoPilot(new TestActor.AutoPilot {
    def run(sender: ActorRef, msg: Any): TestActor.AutoPilot =
      msg match {
        case "stop" ⇒ TestActor.NoAutoPilot
        case x      ⇒ testActor.tell(x, sender); TestActor.KeepRunning
      }
  })
  //#autopilot
  probe.ref ! "hallo"
另一方面,
setAutoPilot
已实现为向
testActor
发送消息:

def setAutoPilot(pilot: TestActor.AutoPilot): Unit = testActor ! TestActor.SetAutoPilot(pilot)
根据,testActor(
probe.ref
)无法在
testActor.SetAutoPilot(pilot)
之前接收
“hallo”
,因为两者都是从同一来源发送的

但是,如果我们使用第三个参与者(使用
system.actorOf(…)
创建)向
probe.ref
发送
“hello”


在某些情况下,在
TestActor.SetAutoPilot(pilot)
之前,
probe.ref
接收到它,从而最终被忽略,这不可能吗?

理论上是的,肯定是的,这基本上是你自己对这个问题的回答。实际上,这是不可能的,因为另一条消息的路径更长,因此需要发生一些非常不寻常的事情,以便它能够更早到达

由于围绕这一点进行的理论研究无法给出任何可行的答案,因此我编写了一个测试来进行实证观察:

Build.sbt:

libraryDependencies ++= Seq(
  "com.typesafe.akka" %% "akka-actor" % "2.5.17"
)

libraryDependencies ++= Seq(
  "com.typesafe.akka" %% "akka-testkit" % "2.5.17",
  "org.scalactic" %% "scalactic" % "3.0.5",
  "org.scalatest" %% "scalatest" % "3.0.5",
  "org.scalacheck" %% "scalacheck" % "1.14.0"
) map (_ % "test")
测试:

实际上,在第二次测试中,我一路重复了10000次,测试总是通过的——而且我还确保如果在向代理发送消息后设置了自动驾驶仪,或者如果testProbe没有响应,测试就会失败

所以,我想说,你所描述的潜在问题要么根本没有发生,要么极不可能发生。当然,该测试非常简单,因此在其他条件下(即阻塞、并行测试执行、CI等),观察结果可能不同,但至少它为最常见/简单的情况提供了一些证据

import scala.concurrent.duration.DurationInt

import akka.actor.{Actor, ActorRef, ActorSystem, Props}
import akka.pattern.ask
import akka.testkit.{TestActor, TestKit, TestProbe}
import akka.util.Timeout
import org.scalatest.{Matchers, PropSpecLike}
import org.scalatest.concurrent.ScalaFutures
import org.scalatest.prop.PropertyChecks

class AutopilotTest extends TestKit(ActorSystem("test"))
  with PropSpecLike with PropertyChecks with ScalaFutures with Matchers {

  private implicit val askTimeout: Timeout = Timeout(100.millis)

  property("Test probe receives autopilot before any other message from same origin") {
    forAll(minSuccessful(1000)) { msg: String =>
      val probe = TestProbe()
      probe.setAutoPilot((sender: ActorRef, msg: Any) => msg match {
        case x => sender ! x; TestActor.KeepRunning
      })
      whenReady((probe.ref ? msg).mapTo[String]) {_ shouldBe msg}
    }
  }

  private class ProxyActor(target: ActorRef) extends Actor {
    override def receive: Receive = { case msg: Any => target forward msg }
  }
  private object ProxyActor { def props(target: ActorRef): Props = Props(new ProxyActor(target)) }

  property("Test probe receives autopilot before any other message from other origin") {
    // set minSuccessuful to as high as you want, but note that current version takes ~38 seconds on my laptop to run
    forAll(minSuccessful(1000)) { msg: String =>
      val probe = TestProbe()
      val proxy = system.actorOf(ProxyActor.props(probe.ref))
      val result = (proxy ? msg).mapTo[String]
      probe.setAutoPilot((sender: ActorRef, msg: Any) => msg match {
        case x => sender ! x; TestActor.KeepRunning
      })
      whenReady(result) {_ shouldBe msg}
    }
  }
}