有没有一种方便的方法可以强制 Grails / Hibernate 从集成测试中重新创建数据库模式?
3 回答
这似乎工作正常,但它显然与 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 中应该很简单。这应该会稍微清理测试代码并通过只转储一次模式来提高效率。
如果您在空数据库中添加以下内容,DataSource.groovy
则会在运行集成测试之前创建:
environments {
test {
dataSource {
dbCreate = "create"
}
}
}
默认情况下,每个集成测试都在测试结束时回滚的事务中执行,因此除非您不使用此默认行为,否则不需要以编程方式重新创建数据库。
更新
根据您的评论,您似乎确实想在进行一些集成测试之前重新创建架构。在那种情况下,我能想到的唯一方法就是运行
- 删除并重新创建架构
- 使用grails schema-export导入新的模式
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
)才能使其正常工作。
好吧,您可以通过 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(不要问我怎么做)