Akka:测试与IO管理器的交互

Chr*_*tey 8 scala akka

我想使用Tcp IO管理器对一个将自己绑定到本地端口的actor进行单元测试,例如

IO(Tcp) ! Bind(self, new InetSocketAddress("localhost", port))
Run Code Online (Sandbox Code Playgroud)

我理想的做法是使用TestProbe代替IO管理器.这将具有不打开TCP连接的单元测试的额外好处.

这是可能的,如果是这样,有人可以提供一个如何做的例子吗?

cmb*_*ter 7

可能有几种方法可以实现这一目标.我会传递一对,希望一个适合你.请记住,调用IO(Tcp)只会产生一个ActorRef.所以你需要做的就是找到一种方法来模拟/步入该调用,然后使用该actor参与.这里有几个代码示例显示了几个解决方案(类似DI):

第一个设置一个方法来返回tcp管理器,然后在单元测试中覆盖它.

class Actor1 extends Actor{
  import context._
  import Tcp._

  def receive = {
    case "connect" =>
      tcp ! Bind(self, new InetSocketAddress("localhost", 8080))
  }

  def tcp:ActorRef = IO(Tcp)
}

class Actor1Spec(_system:ActorSystem) extends TestKit(_system) with Specification{
  import Tcp._

  def this() = this(ActorSystem("test"))

  trait scoping extends Scope{
    val tcpProbe = TestProbe()
    val testRef = TestActorRef(new Actor1{
      override def tcp = tcpProbe.ref
    })
  }

  "A request to connect" should{
    "send a message to connect to the Tcp Manager" in new scoping{
      testRef ! "connect"
      tcpProbe.expectMsg(Bind(testRef, new InetSocketAddress("localhost", 8080)))
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

第二个非常相似,但是将tcp管理器传递给构造函数.

class Actor2(tcpManager:ActorRef) extends Actor{
  import context._
  import Tcp._

  def receive = {
    case "connect" =>
      tcpManager ! Bind(self, new InetSocketAddress("localhost", 8080))
  }

}

class Actor2Spec(_system:ActorSystem) extends TestKit(_system) with Specification{
  import Tcp._

  def this() = this(ActorSystem("test"))

  trait scoping extends Scope{
    val tcpProbe = TestProbe()
    val testRef = TestActorRef(new Actor2(tcpProbe.ref))
  }

  "A request to connect" should{
    "send a message to connect to the Tcp Manager" in new scoping{
      testRef ! "connect"
      tcpProbe.expectMsg(Bind(testRef, new InetSocketAddress("localhost", 8080)))
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这些中的任何一个都可以为你工作,但是再一次,只要你明白这个召唤IO(Tcp)只是回归一个就没有真正的魔力ActorRef