jeudi 23 juin 2016

Actors and unit testing

I have a exception with actors due to how it is instanciated in my tests.

I'm using Play Scala 2.5 with the provided akka library.

Here is my controller:

class MyController @Inject()(implicit context: ExecutionContext, val messagesApi: MessagesApi, system: ActorSystem) extends Controller with I18nSupport {

    val (out, channel) = Concurrent.broadcast[String]
    val listenerActor = system.actorOf(Listener.props, "listener")
    listenerActor ! Start(channel)

    def stream = Action { implicit req =>
        val source = Source.fromPublisher(Streams.enumeratorToPublisher(out))
        Ok.chunked(source via EventSource.flow).as("text/event-stream")
    }

    def myAction = Action.async {
        listenerActor ! NewMessage("Action myAction call")
    }
}

Here is my actor :

object Listener {
  def props = Props[Listener]

  case class Start(out: Concurrent.Channel[String])
  case class NewMessage(message: String)
}

class Listener extends Actor {
  import Listener._

  var out: Option[Concurrent.Channel[String]] = None

  def receive = {
    case Start(out) => this.out = Some(out)
    case NewMessage(msg)    => this.out.map(_.push("{ \"message\": \"" + msg + "\" }"))
  }
}

And my test :

class MyControllerSpec extends PlaySpec with OneAppPerSuite with ScalaFutures with MockitoSugar {

    val messagesApi = app.injector.instanceOf[MessagesApi]
    val ec = app.injector.instanceOf[ExecutionContext]
    val actorSystem = app.injector.instanceOf[ActorSystem]
    val injector = new GuiceInjectorBuilder()
    .overrides(bind[MessagesApi].toInstance(messagesApi))
    .overrides(bind[ExecutionContext].toInstance(ec))
    .overrides(bind[ActorSystem].toInstance(actorSystem))
    .injector

    def myController = injector.instanceOf(classOf[MyController])


    "MyController" should {...}
}

All my tests fail with the exception :

com.google.inject.ProvisionException: Unable to provision, see the following errors:
[info] 
[info] 1) Error injecting constructor, akka.actor.InvalidActorNameException: actor name [listener] is not unique!
[info]   at controllers.MyController.<init>(MyController.scala:29)
[info]   while locating controllers.MyController
[info] 
[info] 1 error
[info]   at com.google.inject.internal.InjectorImpl$2.get(InjectorImpl.java:1025)
[info]   at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1051)
[info]   at play.api.inject.guice.GuiceInjector.instanceOf(GuiceInjectorBuilder.scala:405)
[info]   at controllers.MyControllerSpec.myController(MyControllerSpec.scala:33)
...
Cause: akka.actor.InvalidActorNameException: actor name [listener] is not unique!

How to organize the code so that my actor is instanciated properly ?

Aucun commentaire:

Enregistrer un commentaire