Grails - 重新创建数据库模式以进行集成测试

时间:2013-05-18 21:03:55

标签: testing grails

是否有一种方便的方法可以强制Grails / Hibernate从集成测试中重新创建数据库模式?

3 个答案:

答案 0 :(得分:1)

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

environments {
    test {
        dataSource {
            dbCreate = "create"
        }
    }
}

默认情况下,每个集成测试都在一个在测试结束时回滚的事务中执行,因此,除非您不使用此默认行为,否则不需要以编程方式重新创建数据库。

更新

根据您的评论,您似乎确实希望在某些集成测试之前重新创建架构。在这种情况下,我能想到的唯一方法就是运行


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

首先,这段代码完全没有经过测试,因此需要深深的怀疑和低期望。其次,您可能需要更改集成测试的默认转换行为(使用@Transactional)才能使其正常工作。

答案 1 :(得分:1)

这似乎工作得很好,但它显然与H2非常紧密耦合,所以如果Hibernate插件暴露了api来处理这个问题会很好。

http://h2database.com/html/grammar.html#script

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

}

将此代码提取到仅为测试环境注册的bean中应该是微不足道的。这应该稍微清理测试代码并通过仅转储模式一次来提高效率。

答案 2 :(得分:0)

好吧,您可以通过sessionFactory访问执行任意sql,因此您可以在测试开始时调用grails架构导出,然后在需要时将架构重新导入数据库。

或者,我想知道从外部调用数据库迁移插件是否会完成相同的操作。

或者你可以欺骗grails认为你的域类已经改变并通过https://github.com/grails/grails-core/blob/v2.1.1/grails-hibernate/src/main/groovy/org/codehaus/groovy/grails/plugins/orm/hibernate/HibernatePluginSupport.groovy#L340强制重新加载(不要问我怎么做)