演员和单元测试

时间:2016-06-24 05:33:23

标签: scala unit-testing akka

我对演员有一个例外,因为它在测试中是如何实现的。

我正在使用Play Scala 2.5和提供的akka​​库。

这是我的控制器:

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

这是我的演员:

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 + "\" }"))
  }
}

我的测试:

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 {...}
}

我的所有测试都失败,例外:

    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 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)
[info]   at controllers.MyControllerSpec$$anonfun$1$$anonfun$apply$mcV$sp$7.apply$mcV$sp(MyControllerSpec.scala:94)
[info]   at controllers.MyControllerSpec$$anonfun$1$$anonfun$apply$mcV$sp$7.apply(MyControllerSpec.scala:92)
[info]   at controllers.MyControllerSpec$$anonfun$1$$anonfun$apply$mcV$sp$7.apply(MyControllerSpec.scala:92)
[info]   at org.scalatest.Transformer$$anonfun$apply$1.apply$mcV$sp(Transformer.scala:22)
[info]   at org.scalatest.OutcomeOf$class.outcomeOf(OutcomeOf.scala:85)
[info]   at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
[info]   ...
[info]   Cause: akka.actor.InvalidActorNameException: actor name [listener] is not unique!
[info]   at akka.actor.dungeon.ChildrenContainer$NormalChildrenContainer.reserve(ChildrenContainer.scala:130)
[info]   at akka.actor.dungeon.Children$class.reserveChild(Children.scala:130)
[info]   at akka.actor.ActorCell.reserveChild(ActorCell.scala:374)
[info]   at akka.actor.dungeon.Children$class.makeChild(Children.scala:268)
[info]   at akka.actor.dungeon.Children$class.attachChild(Children.scala:46)
[info]   at akka.actor.ActorCell.attachChild(ActorCell.scala:374)
[info]   at akka.actor.ActorSystemImpl.actorOf(ActorSystem.scala:591)
[info]   at controllers.MyController.<init>(MyController.scala:34)
[info]   at controllers.MyController$$FastClassByGuice$$5133fbab.newInstance(<generated>)
[info]   at com.google.inject.internal.cglib.reflect.$FastConstructor.newInstance(FastConstructor.java:40)

如何组织代码以便我的演员正确实现?

=============================================== ========================== 的更新 我修改了控制器代码以使其工作。它不再使用依赖注入。

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

    val (out, channel) = Concurrent.broadcast[String]
    val listenerActor = ActorSystem("listener").actorOf(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")
    }
}

删除在测试中注入ActorSystem的代码。

1 个答案:

答案 0 :(得分:1)

ActorSystem("a name").actorOf(Props[youractor])

检查此代码是否可以帮助您,它需要一个简洁的名称。