Como reverter um teste de integração com o Slick 3 + Specs2?

Desejo escrever alguns testes de integração para um serviço que executa com facilidade e depois limpar um banco de dados postgresql posteriormente revertendo uma transação, mas não vejo uma maneira de fazê-lo. Entendo que posso testar objetos DBIO que foram compostos juntos e revertê-los, mas não parece possível se eu quiser testar em um nível mais alto de abstração.

No pseudocódigo, quero fazer o seguinte:

StartDbTransaction() // setup
DoSomethingInDB() 
AssertSomething() 
RollBackDbTransaction() // teardown

Por exemplo, se eu tiver isso (simplificado a partir dojogar-silhueta-liso-semente):

class PasswordInfoDAO(db: JdbcBackend#DatabaseDef) {

    // ...
    def remove(loginInfo: LoginInfo): Future[Unit] =
        db.run(passwordInfoSubQuery(loginInfo).delete).map(_ => ())

}

Eu pensei que poderia escrever uma característica ForEach ao longo das linhas doSpecs2 Guide, o que fornece um exemplo genérico:

// 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
    }
}

Então, para slick, eu tentei o seguinte:

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

}

Então planejei usá-lo assim:

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
      }
   }
}

O problema é que o slick 3 ignorará minha sessão (por design) e, em vez disso, usará um pool de sessões, para que minha reversão não faça nada. Eu acho que o Slick tem a expectativa de que você o use no nível das DBIOActions, que podem ser compostas juntas e possivelmente executadas em diferentes contextos. O Slick 2 tinha uma maneira de controlar a sessão com.withSession, mas foi removido.

É a única opção para criar, migrar e descartar um banco de dados de teste a cada teste?

questionAnswers(2)

yourAnswerToTheQuestion