每次测试前我应该如何重置 JPA 控制的数据库?
是否有最佳实践模式可以在单元测试之前使用 JPA 将数据库完全重置为新铺好的模式?我一直在使用带有 hbml2ddl.auto=create-or-drop 的测试持久性单元,并在每次测试之前重新创建 EMF,但我想知道是否有更干净的方法来做到这一点。
Is there a best-practice pattern for completely resetting a database to a freshly-paved schema with JPA before a unit test? I have been using a testing persistence unit with hbml2ddl.auto=create-or-drop and recreating EMFs before each test, but I wonder if there's a cleaner way to do it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
单元测试不应该与数据库对话。
假设您正在为数据访问层编写集成测试,您可以使用 DBUnit 之类的工具,或者您可以创建一个静态测试助手,通过在事务内使用 JPA 查询执行所有删除和插入操作,以编程方式重置数据库状态。
Unit tests should not talk to the database.
Assuming you're writing an integration test for your data access layer, you could use a tool like DBUnit, or you could create a static test helper that programmatically resets your database state by doing all of your deletes and inserts using JPA queries inside of a transaction.
如果您使用快速 Java 数据库(例如 H2 数据库 或 HSQLDB),重置数据库并不是一个大问题。与使用 Oracle / MySQL(或用于生产的任何内容)相比,这将加快您的测试速度,并且将确保您的所有代码都像使用“真实”生产数据库时一样进行测试。
为了获得最大性能,您可以使用 H2 内存(这样您可能不必手动重置数据库 - 如果连接关闭,它会自动重置),或者您可以使用常规持久数据库。要在 H2 中使用后重置数据库,请运行(本机)语句“删除所有对象删除文件”。
Resetting the database is not a big problem if you use a fast Java database such as the H2 database or HSQLDB. Compared to using Oracle / MySQL (or whatever you use for production) this will speed up your tests, and it will ensure all your code is tested as when using the 'real' production database.
For maximum performance, you can use H2 in-memory (that way you may not have to reset the database manually - it's reset automatically if the connection is closed), or you can use a regular persistent database. To reset the database after use in H2, run the (native) statement 'drop all objects delete files'.
DBUnit有很多你需要的东西,我使用Springs测试框架来回滚,每次测试后的事务参见http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/testing.html
DBUnit has much of what you need, I use Springs Testing framework to rollback, transactions after each test see http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/testing.html
不要在每个单元测试之前重置整个数据库模式,而是在每个单元测试结束时重置“数据库环境(特定于当前单元测试)”。
我们有一个实体...
我们正在 prePersist() 方法中为每个 Candidate 实例设置createdDate。这是一个测试用例,断言createdDate设置正确......
这个测试用例将第一次正确运行。但是如果我们第二次运行这个测试用例,它会抛出 ConstraintViolationException,因为 userName 是唯一键。
因此,我认为正确的方法是在每个测试用例结束时“清理数据库环境(特定于当前的单元测试)”。像这样...
在我看来,在每次测试之前重新创建 EMF 非常耗时。
仅当您对 @Entity 注解的类进行了一些影响底层数据库的更改(例如添加/删除列和/或约束)时,才删除并重新创建数据库架构。因此,首先验证架构,如果架构有效,则不要重新创建它,如果无效,则重新创建它。像这样...
现在,如果您一次性运行所有测试用例(扩展 JavaPersistenceTest),则 EMF 将仅创建一次(如果模式无效,则创建两次)。
Don't reset the whole DB schema before every unit test, but reset the "DB environment (which is specific to the current unit test)" at END of each unit test.
We have an entity...
We are setting the createdDate for each Candidate instance in prePersist() method. Here is a test case that asserts that createdDate is getting set properly....
This test case will run properly for the first time. But if we run this test case second time it would throw ConstraintViolationException, because the userName is unique key.
Therefore, I think the right approach is to "clean the DB environment (which is specific to the current unit test)" at end of each test case. Like this...
Recreating EMF before each test is time consuming, IMO.
Drop and recreate the DB schema only if you have made some changes to @Entity annotated class that affects the underlying DB (e.g. adding/removing columns and/or constraints). So first validate the schema, if the schema is valid don't recreate it, and if invalid then recreate it. Like this...
Now, if you run all the test cases(that extend JavaPersistenceTest) in one go, the EMF will be created only once(or twice if the schema was invalid).