如何使用 Spring Test 为每个案例加载一次 DBUnit 测试数据
Spring Test 有助于回滚测试方法中对数据库所做的任何更改。这意味着无需在每次测试方法之前花时间删除/重新加载测试数据。
但如果您使用 @BeforeClass Junit 注释,则会强制数据加载器为静态。这里探讨的问题是:为什么 jUnit 的fixtureSetup 必须是静态的?
如果数据初始化方法是静态的,因此数据连接方法和数据源也必须是静态的……等等……强制一切都是静态的……这是行不通的。此时,我会问 - 当您必须为每个测试删除/重新加载测试数据时,Spring Test 回滚更改的能力有什么好处??!?!
Spring Test helpfully rolls back any changes made to the database within a test method. This means that it is not necessary to take the time to delete/reload the test data before each test method.
But if you use the @BeforeClass Junit annotation, then that forces the data loader to be static. A question that is explored here: Why must jUnit's fixtureSetup be static?
If the data initialization method is static, so must the data connection methods and the data source..and on and on...forcing everything to be static...which won't work. At which point, I ask - what good is Spring Test's ability to rollback changes when you have to delete/reload the test data anyway for every test??!?!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
一种可行的方法是创建一个“数据初始化程序”类,将其添加到也具有数据源的测试 Spring 应用程序上下文中,并将此应用程序上下文连接到您的测试中。这依赖于 Spring 在测试调用之间缓存应用程序上下文的事实。
例如,一个测试超类:
使用
test-application-context.xml
:并且
在此示例中:
DataLoadingTest
;@PostConstruct
注解调用DatabaseInitialiser.load()
;同样,
DatabaseInitialiser
可以有一个注释为@PostDestroy
的方法,以在整个测试运行结束时执行任何必要的回滚。One approach that works is to create a "data initialiser" class, add it to a test Spring application context that also has your data source, and wire this application context into your tests. This relies on the fact that Spring caches the application context between test invocations.
For example, a test superclass:
With
test-application-context.xml
:And
In this example:
DataLoadingTest
;DatabaseInitialiser.load()
, via the@PostConstruct
annotation;DatabaseInitialiser
from the application context, which is already cached;Likewise,
DatabaseInitialiser
can have a method annotated@PostDestroy
to perform any rollback necessary at the end of the whole test run.我们广泛地将 DBUnit 与 Spring Test 结合使用。但我们不使用 DBUnit 功能在测试结束时删除数据。
我们在 @Before 方法中为测试数据插入了一堆 DBUnit 来初始化测试。然后,当测试完成时,我们让 Spring 回滚功能将数据库恢复到原始状态。
我们遇到的最大问题是,必须在每次测试之前加载 DBUnit 数据,这可能会对性能造成重大影响。我们使用 DBUnit 的大多数测试都是只读的,根据某些预定义的行为来测试应用程序的行为。因此,我们习惯于创建主测试,然后在同一事务中批量运行所有细粒度测试。
We use DBUnit in conjunction with Spring Test extensively. But we do not use the DBUnit functionality to delete data at the end of the test.
We put a bunch of DBUnit inserts for our test data in the @Before method to initialise the test. Then when the test is complete we let the spring rollback functionality bring the database back to its original state.
The biggest problem we have with this is that the DBUnit data has to be loaded before each test, which can be a major performance hit. Most of our tests using DBUnit are read only, testing the behaviour of the application based on certain predefined behaviour. So we have a habit of creating master tests that then run all the fine grain tests in a batch within the same transaction.
Spring Test 和 DbUnit 是两个优秀的框架。但将它们结合起来没有意义。由于 Spring Test 在连接上执行回滚,因此会在之后进行清理,而 DbUnit 会清理并将测试数据插入到
@Before
方法中。如果您不依赖于任何动态数据,请使用 Spring,否则请使用 dbUnit。
Spring Test and DbUnit is two excellent frameworks. But it doesn't make sense to combine them. Since Spring Test execute a rollback on the connection, it cleans up afterwards, while DbUnit cleans up and insert test data in the
@Before
method.Use Spring if you're not dependent on any dynamic data and dbUnit otherwise.
方法 用 @BeforeTransaction 注解运行,顾名思义,在每个测试的事务开始之前运行。如果在这种方法中你可以检测到测试数据是否加载,那么就可以在需要的时候加载数据。
但请注意,数据将保留在(内存中)数据库中以供所有后续测试使用。
我们使用它来加载“静态”数据,这些数据在生产环境中也会在启动时引导到我们的数据库中。这样,我们实际上使用完全相同的代码和数据进行测试,而不是依赖可能过时的 (DbUnit) 导出。
Methods annotated with @BeforeTransaction run, like its name suggests, before the transaction of each test is started. If in such method you can detect if the test data is loaded, then one can load the data when needed.
Beware though that the data is left in your (in-memory) database for all subsequent tests.
We use this to load "static" data that would, in a production environment, also be bootstrapped into our database when starting it. This way we actually use exactly the same code and data for our tests, rather than relying on (DbUnit) exports that might become outdated.
您可以创建一个数据初始化程序“bean”,因为该配置仅运行一次。它遵循与主要答案相同的原则,但代码和类较少
You can create a data initializer "bean", since the config is only run once. It follows the same principle as the main answer, but with less code and classes