使用编译时DI时,Play 2.4.6中的功能测试

时间:2016-01-05 21:26:19

标签: scala playframework scalatest

我正在使用Play 2.4.6编译时依赖注入和ScalaTest。控制器的构造函数有很少的参数,在ApplicationLoader中我创建它。 这是代码:

class BootstrapLoader extends ApplicationLoader {
  def load(context: Context) = {
    new AppComponents(context).application
  }
}

class AppComponents(context: Context) extends BuiltInComponentsFromContext(context) with NingWSComponents {
  lazy val router = new Routes(httpErrorHandler, authenticationController, applicationController, assets)
  lazy val applicationController = new controllers.Application()
  lazy val authenticationController = new controllers.Authentication()(configuration, wsApi.client)
  lazy val assets = new controllers.Assets(httpErrorHandler)
}

class Authentication(implicit configuration: Configuration, val ws: WSClient) extends Controller {
  def login = Action { implicit request =>
    Unauthorized(s"${redirectUrl}")
  }
}

class AuthenticationSpec extends PlaySpec with OneAppPerSuite {

  implicit val configuration: Configuration = app.configuration
  implicit val wsClient: WSClient = WS.client(app)

  "when user not logged-in" should {
    "return Status code Unauthorized(401) with redirect url" in  {
      1 mustEqual 2
    }
  }
}

当我运行测试时,我收到以下错误:

[info] Exception encountered when attempting to run a suite with class name: controllers.AuthenticationSpec *** ABORTED ***
[info]   com.google.inject.ProvisionException: Unable to provision, see the following errors:
[info] 
[info] 1) Could not find a suitable constructor in controllers.Authentication. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private.
[info]   at controllers.Authentication.class(Authentication.scala:19)
[info]   while locating controllers.Authentication
[info]     for parameter 1 at router.Routes.<init>(Routes.scala:35)
[info]   while locating router.Routes
[info]   while locating play.api.test.FakeRouterProvider
[info]   while locating play.api.routing.Router
[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:321)
[info]   at play.api.inject.guice.GuiceInjector.instanceOf(GuiceInjectorBuilder.scala:316)
[info]   at play.api.Application$class.routes(Application.scala:112)
[info]   at play.api.test.FakeApplication.routes(Fakes.scala:197)
[info]   at play.api.Play$$anonfun$start$1.apply$mcV$sp(Play.scala:90)
[info]   at play.api.Play$$anonfun$start$1.apply(Play.scala:87)
[info]   at play.api.Play$$anonfun$start$1.apply(Play.scala:87)
[info]   at play.utils.Threads$.withContextClassLoader(Threads.scala:21)

FakeApplication使用GuiceApplicationBuilder,这当然不起作用。

我应该怎么做才能进行这样的测试?

由于

5 个答案:

答案 0 :(得分:1)

override implicit lazy val app = new BootstrapLoader().load(
ApplicationLoader.createContext(
  new Environment(
    new File("."), ApplicationLoader.getClass.getClassLoader, Mode.Test)))

适用于Play 2.5.1

答案 1 :(得分:0)

您收到错误,因为测试甚至无法启动应用程序。这种情况正在发生,因为您在控制器中使用了依赖注入(如错误消息所示),您需要将它们声明为classes,而不是objects。正如您在docs所见:

package controllers

import play.api.mvc._

class Application extends Controller {
    def index = Action {
        Ok("It works!")
    }
}

如果你的控制器有一些依赖注入,你应该在你的控制器构造函数中使用@Inject注释(再次请参阅docs)。每个实例:

package controllers

import play.api.mvc._
import play.api.libs.ws._
import javax.inject._

class Application @Inject() (ws: WSClient) extends Controller {
    // ...
}

如果您使用它而不是运行时DI,也可以阅读Compile Time Dependency Injection docs

答案 2 :(得分:0)

如果您使用specs2,您可以这样做。见http://loicdescotte.github.io/posts/play24-compile-time-di/ 但是你松开了那个漂亮的api。

Scalatest / scalatest-plus用DI(guice)做了一些时髦的事情:(

答案 3 :(得分:0)

我遇到了和你一样的问题。我没有一个令人满意的解决方案,以下只是一个解决方法: 我最终放了

implicit def client:WSClient = NingWSClient()

在我的WithApplicationLoader类

我还发现https://github.com/leanovate/play-mockws允许你模拟ws调用。但这不是我们想要的。

答案 4 :(得分:0)

我的猜测是OneAppPerSuite特征没有使用您的自定义应用程序加载器。您可能需要覆盖来自该特征的应用程序构造并使其使用您的自定义装载程序。

看起来在这里有一个使用scalatest的例子:http://mariussoutier.com/blog/2015/12/06/playframework-2-4-dependency-injection-di/