【发布时间】:2016-06-24 05:33:22
【问题描述】:
由于在我的测试中实例化的方式,我对演员有一个例外。
我正在使用 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 的代码。
【问题讨论】:
标签: scala unit-testing akka