我使用anorm进行播放框架,我有以下服务类:
@javax.inject.Singleton
class ProductService @Inject() (dbApi: DBApi) {
private val DB = dbApi.database("default")
def save(product: Product) = {
DB.withConnection { implicit connection =>
....
}
}
}
这里有两个问题:
1)我不希望在每个Service类中添加行private val DB = dbApi.database("default")
。抽象这个的最佳方法是什么?
2)我还希望数据源可配置,以便在编写集成测试时可以传递测试数据源
测试类:
import models.ProductService
import org.scalatestplus.play.{OneAppPerSuite, PlaySpec}
import play.api.db.Databases
class ProductSpec extends PlaySpec with OneAppPerSuite {
var productService: ProductService = app.injector.instanceOf(classOf[ProductService])
Databases.withDatabase(
driver = "com.mysql.jdbc.Driver",
url = "jdbc:mysql://localhost/playtest",
config = Map(
"user" -> "test",
"password" -> "demo"
)
) { database =>
import play.api.db.evolutions._
Evolutions.applyEvolutions(database)
"Product" should {
"be retrieved by Id" in {
val product = productService.get(23)
product.get.name must equal("mobile")
}
}
}
}
有什么建议吗?
答案 0 :(得分:2)
您可以注入database
对象本身而不是DBApi
。顺便说一句,Guice的最佳实践之一是inject only direct dependencies。所以,你的例子可能是这样的:
import play.api.db.Database
@Singleton
class ProductService @Inject() (database: Database) {
def save(product: Product) = {
database.withConnection { implicit connection =>
....
}
}
}
当然,如果你想注入一个特定的数据库(而不是"default"
),你可以像这样注释属性:
import play.api.db.Database
import play.db.NamedDatabase
@Singleton
class ProductService @Inject() (@NamedDatabase("customers") database: Database) {
def save(product: Product) = {
database.withConnection { implicit connection =>
....
}
}
}
并且,在您的测试中,您可以根据需要创建Database
并手动将其注入您的服务。查看有关如何执行此操作的详细信息at the docs。