Akka: Testing Interactions with IO Managers

I would like to have a unit test actor who associates itself with a local port using the Tcp IO dispatcher, for example,

IO(Tcp) ! Bind(self, new InetSocketAddress("localhost", port)) 

What I would like to do is get a TestProbe instead of an IO manager. This will have the additional benefit of unit test not opening a TCP connection.

Is this possible, and if so, can someone please provide an example of how to do this?

+8
scala akka
source share
1 answer

There are probably several ways to achieve this. I will give the pair in the hope that you will work for you. ActorRef in mind that an IO(Tcp) call only creates an ActorRef . So all you have to do is find a way to mock / step in front of this call and then work with this ref actor. Here are some code examples showing a couple of solutions (sort of like a DI):

This first sets up a method to return the tcp manager and then overrides it in unit test.

 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))) } } } 

This second one is very similar, but instead goes to the tcp manager in the constructor.

 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))) } } } 

Any of these may work for you, but then again, there is no real magic if you understand that calling IO(Tcp) just returns an ActorRef

+6
source share

All Articles