Подтвердить что ты не робот

Как запустить ScalaTest с помощью Guice DI и Slick?

Я не знаю, как настроить GuiceApplicationBuilder таким образом, что я могу загрузить контроллеры, которым требуется вставить DatabaseConfigProvider.

Я хотел бы указать альтернативную базу данных postgres для тестирования или базу данных в памяти (если это возможно).

код

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$1.apply(Application.scala:234)
[info]   at play.api.Application$$anonfun$instanceCache$1.apply(Application.scala:234)
[info]   at play.utils.InlineCache.fresh(InlineCache.scala:69)
[info]   at play.utils.InlineCache.apply(InlineCache.scala:55)
[info]   ...
4b9b3361

Ответ 1

Вам нужно добавить конфигурацию в GuiceApplicationBuilder(), тогда все должно быть обработано автоматически с помощью платформы воспроизведения. Что-то вроде этого должно помочь:

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

Ответ 2

В этом подходе есть немного настройки, но конечный результат справедлив. Прежде всего, начните с реализации своего собственного GuiceApplicationLoader путем его расширения. См. Мой ответ, как его реализовать. Почему ваш собственный загрузчик приложений? Вы можете указать различные конфигурации/модули в режимах Prod/Dev/Test, а также различные источники данных. У вашего основного application.conf не будет настроен источник данных. Вместо этого вы переместили бы его в конфигурации, специфичные для среды, которые в любом случае будут объединены с основной конфигурацией загрузчиком приложений. Ваш dev.conf будет выглядеть следующим образом:

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

И теперь трюк заключается в том, чтобы использовать то же имя источника данных, в данном случае default, для всех других конфигураций (URL-адрес базы данных, драйверы, учетные данные и т.д. были бы разными). При такой настройке ваш evolutions будет применен к вашей тестовой и dev-базе данных. Ваш test.conf может выглядеть следующим образом:

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

В ваших тестах используйте WithApplicationLoader с вашим пользовательским загрузчиком приложений и тем самым.

@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")
        }

    }

}

В самом тесте у вас есть доступ к значению app: Application:

val service = app.injector.instanceOf(classOf[IService])