scala - integracion - play framework web server
Pruebas funcionales en Play 2.4.6 cuando se utiliza el tiempo de compilaciĆ³n DI (5)
Está recibiendo un error porque las pruebas ni siquiera pueden iniciar una aplicación. Eso está sucediendo porque estás usando Dependency Injection en tus controladores (como sugiere el mensaje de error) y necesitas declararlos como classes
, en lugar de como objects
. Como puedes ver en los documentos :
package controllers
import play.api.mvc._
class Application extends Controller {
def index = Action {
Ok("It works!")
}
}
Si tu controlador tiene alguna dependencia para ser inyectado, debes usar la anotación @Inject
en tu constructor de controlador (de nuevo, por favor mira los documentos ). Por ejemplo:
package controllers
import play.api.mvc._
import play.api.libs.ws._
import javax.inject._
class Application @Inject() (ws: WSClient) extends Controller {
// ...
}
También puede leer los documentos de Inyección de Dependencia de Tiempo de Compilación si lo está usando en lugar del tiempo de ejecución DI.
Estoy usando Play 2.4.6 con inyección de dependencia de tiempo de compilación y ScalaTest. El constructor del controlador tiene pocos parámetros, y en un ApplicationLoader lo creo. Aquí está el código:
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
}
}
}
Cuando ejecuto la prueba recibo el siguiente error:
[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
usa GuiceApplicationBuilder
, que por supuesto no funciona.
¿Qué debo hacer para ejecutar tales pruebas?
Gracias
Estoy enfrentando el mismo problema que tú. No tengo una solución satisfactoria, la siguiente es una mera solución: terminé poniendo
implicit def client:WSClient = NingWSClient()
en mi clase WithApplicationLoader
También encontré https://github.com/leanovate/play-mockws que le permite simular las llamadas de ws. Pero eso no es lo que queremos aquí.
Si usa specs2 puede hacerlo. ver http://loicdescotte.github.io/posts/play24-compile-time-di/ Pero pierdes la buena API.
Scalatest / scalatest-plus ha hecho algo funky con DI (guice) :(
supongo que el rasgo OneAppPerSuite
no está usando su cargador de aplicaciones personalizado. es posible que deba anular la construcción de la aplicación que proviene de ese rasgo y hacer que use su cargador personalizado.
parece que hay un ejemplo que usa Scalatest aquí: http://mariussoutier.com/blog/2015/12/06/playframework-2-4-dependency-injection-di/
override implicit lazy val app = new BootstrapLoader().load(
ApplicationLoader.createContext(
new Environment(
new File("."), ApplicationLoader.getClass.getClassLoader, Mode.Test)))
Funciona en Play 2.5.1