用于创建datasource
我有
object MyDataSource {
priavte lazy val dataSource: javax.sql.DataSource = {
val ds = new BasicDataSource
val conf = ConfigFactory.load()
val url = conf.getString("jdbc-url")
val driver = conf.getString("jdbc-driver")
val username = conf.getString("db-username")
val password = conf.getString("db-password")
val port = conf.getString("db-port")
val maxActive = conf.getInt("max-active")
val maxIdle = conf.getInt("max-idle")
val initSize = conf.getInt("init-size")
ds.setDriverClassName(driver)
ds.setUsername(username)
ds.setPassword(password)
ds.setMaxActive(maxActive)
ds.setMaxIdle(maxIdle)
ds.setInitialSize(initSize)
ds.setUrl(url)
ds
}
lazy val database = Database.forDataSource(dataSource)
}
MyDataSource
使用如下
def insertCompany = {
MyDataSource.database.withSession{ implicit session =>
company.insert(companyRow)
}
}
现在进行测试我有trait DatabaseSpec
加载测试数据库(指向测试数据库)配置并具有以下夹具
def withSession(testCode: Session => Any) {
val session = postgres.createSession()
session.conn.setAutoCommit(false)
try {
testCode(session)
} finally {
session.rollback()
session.close()
}
}
然后测试代码可以混合在DatabaseSpec
中并使用withSession
来测试交易代码。
现在的问题是保持MyDataSource.database.withSession
在DataSource
中从insertCompany
抽象出来的最佳做法是什么,以便可以使用DatabaseSpec
测试方法并指向测试数据库?
答案 0 :(得分:3)
能够交换价值的最佳方式,例如prod和测试,是通过参数化该值中的代码。 E.g。
def insertCompany(db: Database) = db.withSession(company.insert(companyRow)(_))
或
class DAO(db:Database){
def insertCompany = db.withSession(company.insert(companyRow)(_))
}
保持简单。避免不必要的复杂性,如Cake模式,DI框架或mixin组合。
如果你需要传递多个值...将它们聚合成一个" config" -class。编写多个具有不同目的的配置类来定位不同的东西,如果你想避免在积累的东西时编写一个巨大的配置类。
如果您发现自己将配置对象传递给所有功能,则可以将它们标记为隐式,这至少可以节省呼叫站点代码开销。或者您可以使用类似scalaz的monadic函数组合来避免调用站点和定义站点代码开销以传递配置。它有时被称为Reader monad,但它只是for-comprehension启用的1参数函数组合。
Slick 2.2将附带开箱即用的东西,让你想要的东西变得非常简单。
此外,这是我正在使用的一种方法,一个可组合的配置对象" TMap"。此代码示例逐步显示了如何通过参数化函数从全局导入中获取并使其隐式使用TMap并删除大多数样板:https://github.com/cvogt/slick-action/blob/0.1/src/test/scala/org/cvogt/di/TMapTest.scala#L49