scala - Play Framework 2.5 测试 ApplicationLifecycle Guice Specs2 设置

标签 scala guice playframework-2.5

我正在尝试使用 play2-reactivemongo 运行一些功能测试。我会尽可能具体,但如果有遗漏,请告诉我。

我的依赖项在这里

libraryDependencies ++= Seq(
  cache,
  "org.reactivemongo" %% "play2-reactivemongo" %  "0.12.0",
  "com.mohiva" %% "play-silhouette" % "4.0.0",
  "com.mohiva" %% "play-silhouette-testkit" % "4.0.0" % "test",
  specs2 % Test
)

MongoUserDao.scala

import play.modules.reactivemongo._
import play.modules.reactivemongo.json._
import reactivemongo.play.json.collection.JSONCollection

class MongoUserDao @Inject() (val reactiveMongoApi: ReactiveMongoApi) extends UserDao {
  val usersFuture = reactiveMongoApi.database.map(_.collection[JSONCollection]("users"))
...
}

DaoSpecResources.scala

trait DaoSpecResources {

  val timeout = DurationInt(10).seconds

  val fakeApp = new GuiceApplicationBuilder()
    .in(Mode.Test)
    .configure(
      "play.modules.enabled" -> List("play.modules.reactivemongo.ReactiveMongoModule"),
      "mongodb.uri" -> "mongodb://localhost:27017/test"
    )
    .build

  val reactiveMongoApi = fakeApp.injector.instanceOf[ReactiveMongoApi]
  ...
}

当我尝试运行测试时出现此错误

[error] cannot create an instance for class daos.UserDaoSpec
[error]   caused by com.google.inject.CreationException: Unable to create injector, see the following errors:
[error]
[error] 1) No implementation for play.api.inject.ApplicationLifecycle was bound.
[error]   while locating play.api.inject.ApplicationLifecycle
[error]     for parameter 1 at services.ApplicationTimer.<init>(ApplicationTimer.scala:24)
[error]   at Module.configure(Module.scala:23) (via modules: com.google.inject.util.Modules$OverrideModule -> Module)
[error]
[error] 1 error

最佳答案

这是由 app/services/ApplicationTimer.scala 引起的,它依赖于 ApplicationLifecycle,但您尚未将任何实现绑定(bind)到 ApplicationLifecycle >。 ApplicationTimer 是每个新 Play 项目中包含的演示。如果不需要它,您可能应该完全删除它,否则,如果在测试模式下运行,至少禁用它。请参阅disabling modulesoverriding modules .

解决方案

但是,由于 DefaultReactiveMongoApi 也依赖于 ApplicationLifecycle,因此您需要提供与 ApplicationLifecycle 实现的绑定(bind)。最简单的方法:

import play.api.inject.{ ApplicationLifecycle, DefaultApplicationLifecycle }
import play.api.inject.bind

trait DaoSpecResources {

  val timeout = DurationInt(10).seconds

  val fakeApp = new GuiceApplicationBuilder()
    .in(Mode.Test)
    .configure(
      "play.modules.enabled" -> List("play.modules.reactivemongo.ReactiveMongoModule"),
      "mongodb.uri" -> "mongodb://localhost:27017/test"
    )
    .bindings(bind[ApplicationLifecycle].to[DefaultApplicationLifecycle])
    .build

  val reactiveMongoApi = fakeApp.injector.instanceOf[ReactiveMongoApi]

  val lifecycle = fakeApp.injector.instanceOf[DefaultApplicationLifecycle]
  def stopApp = lifecycle.stop()

}

(添加了 5 行:导入、绑定(bind)生命周期stopApp)

然后,在您的测试规范中,在末尾添加 step(stopApp),如下所示:

class FooSpec extends PlaySpecification with DaoSpecResources {

    // Your examples...

    step(stopApp)

}

替代解决方案

就个人而言,我会创建一个扩展 SpecificationPlaySpecification 的特殊特征,它会自动设置和拆除所有内容,例如 in this example from specs2 documentation .

trait PlayWithMongoSpecification extends PlaySpecification {

  val timeout = DurationInt(10).seconds

  val fakeApp = new GuiceApplicationBuilder()
    .in(Mode.Test)
    .configure(
      "play.modules.enabled" -> List("play.modules.reactivemongo.ReactiveMongoModule"),
      "mongodb.uri" -> "mongodb://localhost:27017/test"
    )
    .bindings(bind[ApplicationLifecycle].to[DefaultApplicationLifecycle])
    .build

  val reactiveMongoApi = fakeApp.injector.instanceOf[ReactiveMongoApi]

  val lifecycle = fakeApp.injector.instanceOf[DefaultApplicationLifecycle]
  def stopApp = lifecycle.stop()

  override def map(fs: =>Fragments) = fs ^ step(stopApp)

}

class FooSpec extends PlayWithMongoSpecification {

    // Your examples...

}

您可以考虑将 reactiveMongoApi 设为 lazy val

关于scala - Play Framework 2.5 测试 ApplicationLifecycle Guice Specs2 设置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40721172/

相关文章:

java - 使用 guice 为客户端 sdk/library 设计模式进行依赖注入(inject)

java - 使用 Guice 和 "Law of Demeter"进行依赖注入(inject)

scala - 如何在Scala Play框架中对服务器启动执行操作?

scala - lift-json XPath\\operator 根据 num 匹配有不同的返回类型

scala - 解析器组合器,分离语法和 AST 构造

scala - 如何定义在免费应用程序中使用的递归代数?

java - 基于命令行参数交换 Guice 绑定(bind)的最佳方法

Scala 将隐式函数应用于集合

json - 从 anyContent 获取内容为 Json

scala - 在 Play 2.5.2 中注入(inject)当前应用