简体   繁体   English

Play Framework 2.5测试应用程序Lifecycle Guice Specs2设置

[英]Play Framework 2.5 Test ApplicationLifecycle Guice Specs2 setup

I am trying to run some functional tests with play2-reactivemongo . 我正在尝试使用play2-reactivemongo运行一些功能测试。 I will try to be as concrete as possible, but if something is missing please let me know. 我会尽量保持具体,但如果缺少某些内容,请告诉我。

My dependencies are here 我的依赖在这里

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
)

In MongoUserDao.scala 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"))
...
}

In DaoSpecResources.scala 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]
  ...
}

When I try to run the test I get this error 当我尝试运行测试时,出现此错误

[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

This is caused by app/services/ApplicationTimer.scala , which depends on ApplicationLifecycle , but you haven't bound any implementation to ApplicationLifecycle . 这是由app/services/ApplicationTimer.scala引起的,它取决于ApplicationLifecycle ,但是您尚未将任何实现绑定到ApplicationLifecycle ApplicationTimer is a demo included in every new Play project. ApplicationTimer是每个新的Play项目中包含的演示。 You should probably remove it completely if you don't need it, otherwise at least disable it if running in test mode. 如果不需要它,可能应该将其完全删除;否则,如果在测试模式下运行,则至少应将其禁用。 See disabling modules and overriding modules . 请参阅禁用模块覆盖模块

Solution

However, since DefaultReactiveMongoApi also depends on ApplicationLifecycle , you'll need to provide a binding to an implementation of ApplicationLifecycle . 但是,由于DefaultReactiveMongoApi也依赖于ApplicationLifecycle ,因此您需要提供对ApplicationLifecycle的实现的绑定。 The easiest way: 最简单的方法:

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

}

(added 5 lines: imports, bindings , lifecycle and stopApp ) (添加了5行:导入, bindingslifecyclestopApp

Then, in your test spec, add step(stopApp) at the end, like so: 然后,在测试规范中,最后添加step(stopApp) ,如下所示:

class FooSpec extends PlaySpecification with DaoSpecResources {

    // Your examples...

    step(stopApp)

}

Alternative solution 替代解决方案

Personally, I'd create a specialized trait extending Specification or PlaySpecification which would set up and tear down everything automatically, like in this example from specs2 documentation . 就个人而言,我将创建一个特殊的特性来扩展SpecificationPlaySpecification ,这些特性将自动设置和PlaySpecification所有内容, 例如specs2文档中的示例

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

}

You may consider making reactiveMongoApi a lazy val . 您可以考虑将reactiveMongoApilazy val

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM