如何使用 Guice DI 和 Slick 运行 ScalaTest?
How to run ScalaTest with Guice DI and 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() )
...
}
}
堆栈跟踪
[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] ...
您需要为您的 GuiceApplicationBuilder()
添加一个配置,然后一切都应该由 play 框架自动处理。这样的事情应该有所帮助:
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()
这种方法有一些设置,但最终结果是公平的。首先,通过扩展实现您自己的 GuiceApplicationLoader
。看我的。为什么你自己的应用程序加载器?您可以为每个 Prod/Dev/Test
模式指定不同的 configs/modules - 以及不同的数据源。您的主 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"
}
}
}
现在的诀窍是对所有其他配置(数据库 url、驱动程序、凭据等会有所不同)。通过这样的设置,您的 evolutions
将应用于您的测试和开发数据库。您的 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])
我不知道如何配置 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() )
...
}
}
堆栈跟踪
[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] ...
您需要为您的 GuiceApplicationBuilder()
添加一个配置,然后一切都应该由 play 框架自动处理。这样的事情应该有所帮助:
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()
这种方法有一些设置,但最终结果是公平的。首先,通过扩展实现您自己的 GuiceApplicationLoader
。看我的Prod/Dev/Test
模式指定不同的 configs/modules - 以及不同的数据源。您的主 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"
}
}
}
现在的诀窍是对所有其他配置(数据库 url、驱动程序、凭据等会有所不同)。通过这样的设置,您的 evolutions
将应用于您的测试和开发数据库。您的 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])