Testing Grails-为集成测试重新创建数据库模式

Testing Grails-为集成测试重新创建数据库模式,testing,grails,Testing,Grails,有没有一种方便的方法可以强制Grails/Hibernate从集成测试重新创建数据库架构?如果在数据源中添加以下内容。groovy在运行集成测试之前将创建一个空数据库: environments { test { dataSource { dbCreate = "create" } } } 默认情况下,每个集成测试都在测试结束时回滚的事务中执行,因此除非您不使用此默认行为,否则不需要通过编程方式重新创建数据库 更新 根据您

有没有一种方便的方法可以强制Grails/Hibernate从集成测试重新创建数据库架构?

如果在
数据源中添加以下内容。groovy在运行集成测试之前将创建一个空数据库:

environments {
    test {
        dataSource {
            dbCreate = "create"
        }
    }
}
默认情况下,每个集成测试都在测试结束时回滚的事务中执行,因此除非您不使用此默认行为,否则不需要通过编程方式重新创建数据库

更新 根据您的评论,您似乎确实希望在进行一些集成测试之前重新创建模式。在这种情况下,我唯一能想到的办法就是逃跑

  • 删除并重新创建架构
  • 用于导入新架构

类MyIntegrationTest{
会话工厂会话工厂
/**
*执行SQL语句的助手
*@param jdbcWork传递用于执行JDBC语句的Sql对象的闭包
*/
私有doJdbcWork(闭包jdbcWork){
sessionFactory.currentSession.doWork(
新作品(){
@凌驾
void execute(连接)抛出SQLException{
//不要自己关闭此Sql实例
Sql=新Sql(连接)
jdbcWork(sql)
}
}
)
}
私有重新创建架构(){
doJdbcWork{Sql->
//使用sql对象删除数据库并创建新的空白数据库
//类似于以下内容的内容可能适用于MySQL
execute(“删除数据库我的模式”)
execute(“创建数据库我的模式”)
}
//生成DDL并导入它
//必须有一种更好的方法从内部执行grails命令
//集成测试,但不幸的是我不知道它是什么
“grails测试架构导出”。execute()
}
@试验
void myTestMethod(){
重新创建架构()
//现在做测试
}
}

首先也是最重要的一点,这段代码完全没有经过测试,所以请以深刻的怀疑和低期望来对待它。其次,您可能需要更改集成测试的默认跨国家行为(使用
@Transactional
)以使其正常工作。

您可以通过sessionFactory执行任意sql,因此,您可以在测试开始时调用grails模式导出,然后在需要时将该模式重新导入数据库

或者,我想知道外部调用数据库迁移插件是否也能实现同样的效果


或者,您可以欺骗grails,使其认为您的域类已更改,并通过强制重新加载(不要问我如何)

这似乎工作正常,但它显然与H2紧密耦合,因此如果Hibernate插件公开了一个api来处理这一问题,那就太好了


将此代码提取到仅为测试环境注册的bean中应该很简单。这将稍微清理测试代码,并通过只需转储一次模式来提高效率

谢谢,但恐怕这并不能回答我的问题。我有一个(相当)好的理由想在一些集成测试之前强制使用一个新的模式。谢谢你的努力!是的,也许这就是解决问题的方法,尽管我对新Grails过程的分支有点怀疑。我知道H2有一些用于执行sql脚本的内置功能。也许最好的办法是尽早转储数据库,然后在每次测试之前从文件中加载它。您是需要在运行脚本之前清理数据库,还是需要自己清理数据库?另外,在管理模式下运行是否需要执行任何特殊操作?只是使用一个管理员用户?
class MyIntegrationTest {

    SessionFactory sessionFactory

    /**
     * Helper for executing SQL statements
     * @param jdbcWork A closure that is passed an <tt>Sql</tt> object that is used to execute the JDBC statements
     */
    private doJdbcWork(Closure jdbcWork) {

        sessionFactory.currentSession.doWork(

            new Work() {
                @Override
                void execute(Connection connection) throws SQLException {

                    // do not close this Sql instance ourselves
                    Sql sql = new Sql(connection)
                    jdbcWork(sql)
                }
            }
        )
    }

    private recreateSchema() {

        doJdbcWork {Sql sql ->
           // use the sql object to drop the database and create a new blank database
           // something like the following might work for MySQL
           sql.execute("drop database my-schema")
           sql.execute("create database my-schema")
        }

        // generate the DDL and import it
        // there must be a better way to execute a grails command from within an
        // integration test, but unfortunately I don't know what it is            
        'grails test schema-export export'.execute()
    }

    @Test 
    void myTestMethod() {
        recreateSchema() 
        // now do the test
    }
}
class SomethingTestingTransactionsSpec extends IntegrationSpec {

    static transactional = false // Why I need this

    SessionFactory sessionFactory // Injected by Spring
    DataSource dataSource // Also injected

    File schemaDump
    Sql sql    


    void setup() {
        sql = new Sql(dataSource)
        schemaDump = File.createTempFile("test-database-dump", ".sql") // Java 7 API
        sql.execute("script drop to ${schemaDump.absolutePath}")
    }

    void cleanup() {
        sql.execute("runscript from ${schemaDump.absolutePath}")
        sessionFactory.currentSession.clear()
        schemaDump.delete()
    }

    // Spock tests ...

}