Comment exécuter ScalaTest avec Guice DI et Slick?

Je ne sais pas comment configurer GuiceApplicationBuilder de manière à pouvoir charger des contrôleurs qui nécessitent l'injection d'un DatabaseConfigProvider .

j'aimerais spécifier une base de données alternative postgres pour tester, ou une base de données en mémoire (si cela est possible).

Code

class   User
extends MySpecs
with    OneAppPerTest
{
    override def newAppForTest( testData: TestData ) = new GuiceApplicationBuilder()
        // Somehow bind a database here, I guess?
        .build()

    "A test" should "test" in
    {
        val result = Application.instanceCache[api.controller.User]
            .apply( app )
            .list()( FakeRequest() )

        ...
    }
}

Stacktrace

[info] - should return an entity *** FAILED ***
[info]   com.google.inject.ConfigurationException: Guice configuration errors:
[info] 
[info] 1) No implementation for play.api.db.slick.DatabaseConfigProvider was bound.
[info]   while locating play.api.db.slick.DatabaseConfigProvider
[info]     for parameter 1 at api.controller.User.<init>(User.scala:22)
[info]   while locating api.controller.User
[info] 
[info] 1 error
[info]   at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1042)
[info]   at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1001)
[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$$anonfun$instanceCache.apply(Application.scala:234)
[info]   at play.api.Application$$anonfun$instanceCache.apply(Application.scala:234)
[info]   at play.utils.InlineCache.fresh(InlineCache.scala:69)
[info]   at play.utils.InlineCache.apply(InlineCache.scala:55)
[info]   ...
23
demandé sur Taig 2015-07-31 21:29:13

2 réponses

vous devez ajouter une configuration à votre GuiceApplicationBuilder() , alors tout doit être géré automatiquement par le framework de jeu. Quelque chose comme ceci devrait aider:

val app = new GuiceApplicationBuilder()
        .configure(
            Configuration.from(
                Map(
                    "slick.dbs.YOURDBNAME.driver" -> "slick.driver.H2Driver$",
                    "slick.dbs.YOURDBNAME.db.driver" -> "org.h2.Driver",
                    "slick.dbs.YOURDBNAME.db.url" -> "jdbc:h2:mem:",

                    "slick.dbs.default.driver" -> "slick.driver.MySQLDriver$",
                    "slick.dbs.default.db.driver" -> "com.mysql.jdbc.Driver"
                )
            )
        )
        .in(Mode.Test)
        .build()
7
répondu Mateusz Dymczyk 2015-08-13 04:24:55

il y a un peu de mise en place dans cette approche, mais le résultat final est juste. Tout d'abord, commencez par mettre en œuvre votre propre GuiceApplicationLoader en l'étendant. Voir ma réponse comment la mettre en œuvre . Pourquoi votre propre Application loader? Vous pouvez spécifier différentes configs / modules par Prod/Dev/Test modes - ainsi que différentes sources de données. Votre principal application.conf n'aurait pas de source de données configurée. Au lieu de cela, vous devriez passer à l'environnement spécifique configurations qui seraient fusionnées avec la configuration principale par application loader de toute façon. Votre dev.conf ressemblerait à ceci:

slick.dbs {
  default {
    driver = "slick.driver.PostgresDriver$",
    db {
      driver = "org.postgresql.Driver",
      url = "jdbc:postgresql://localhost:5432/dev",
      user = "postgres"
      password = "postgres"
    }
  }
}

et le truc est maintenant d'utiliser même nom de la source de données, dans ce cas default , pour toutes les autres configurations (url de la base de données, pilotes, justificatifs d'identité, etc. serait différent). Avec une telle configuration, votre evolutions sera appliqué à votre base de données de test et de développement. Votre test.conf pourrait ressembler à

slick.dbs {
  default {
    // in memory configuration
  }
}

dans vos tests, utilisez WithApplicationLoader avec votre chargeur d'application personnalisé à la place et c'est tout.

@RunWith(classOf[JUnitRunner])
class ApplicationSpec extends Specification {

    "Application" should {

        "return text/html ok for home" in new WithApplicationLoader(new CustomApplicationLoader) {
          val home = route(FakeRequest(routes.ApplicationController.home())).get
          status(home) must equalTo(OK)
          contentType(home) must beSome.which(_ == "text/html")
        }

    }

}

dans le test lui-même, vous avez un accès à app: Application valeur:

val service = app.injector.instanceOf(classOf[IService])
2
répondu Mon Calamari 2015-08-18 08:17:50