【发布时间】:2016-04-26 14:50:28
【问题描述】:
我想为运行流畅的服务编写一些集成测试,然后通过回滚事务来清理 postgresql 数据库,但我看不到这样做的方法。我知道我可以测试组合在一起的 DBIO 对象并将它们回滚,但如果我想在更高的抽象级别上进行测试,这似乎是不可能的。
在伪代码中,我想这样做:
StartDbTransaction() // setup
DoSomethingInDB()
AssertSomething()
RollBackDbTransaction() // teardown
例如,如果我有这个(从play-silhouette-slick-seed 简化):
class PasswordInfoDAO(db: JdbcBackend#DatabaseDef) {
// ...
def remove(loginInfo: LoginInfo): Future[Unit] =
db.run(passwordInfoSubQuery(loginInfo).delete).map(_ => ())
}
我想我可以按照Specs2 Guide 的方式编写一个 ForEach 特征,这给出了一个通用示例:
// a transaction with the database
trait Transaction
trait DatabaseContext extends ForEach[Transaction] {
// you need to define the "foreach" method
def foreach[R: AsResult](f: Transaction => R): Result = {
val transaction = openDatabaseTransaction
try AsResult(f(transaction))
finally closeDatabaseTransaction(transaction)
}
// create and close a transaction
def openDatabaseTransaction: Transaction = ???
def closeDatabaseTransaction(t: Transaction) = ???
}
class FixtureSpecification extends mutable.Specification with DatabaseContext {
"example 1" >> { t: Transaction =>
println("use the transaction")
ok
}
"example 2" >> { t: Transaction =>
println("use it here as well")
ok
}
}
所以对于 slick,我尝试了这个:
override def foreach[R: AsResult](f: JdbcBackend#DatabaseDef => R): Result = {
val db = dbConfig.db
val session = db.createSession()
session.conn.setAutoCommit(false)
val result = AsResult(f(db))
session.conn.rollback()
result
}
然后我打算像这样使用它:
class PasswordInfoDAOSpec(implicit ee: ExecutionEnv)
extends Specification with DatabaseContext {
"password" should {
"be removed from db" in { db =>
// arrange
db.run(...) // something to set up the database
// act
PasswordInfoDAO(db).remove(loginInfo).await
// assert
PasswordInfoDAO(db).find(loginInfo) must be None.await
}
}
}
问题是 slick 3 将忽略我的会话(按设计),而是使用会话池,因此我的回滚不会做任何事情。我认为 Slick 期望您应该在 DBIOActions 级别使用它,这些 DBIOActions 可以组合在一起并可能在不同的上下文中执行。 Slick 2 有办法用.withSession 控制会话,但它被删除了。
是否是每次测试都创建、迁移和删除测试数据库的唯一选项?
【问题讨论】:
标签: scala playframework slick specs2