dbunit 性能最佳实践
Posted
技术标签:
【中文标题】dbunit 性能最佳实践【英文标题】:dbunit best practices for performance 【发布时间】:2012-01-17 06:58:00 【问题描述】:除了实际 dbunit 网站上推荐的那些之外,还有哪些可以大大加快测试速度并保持可维护性的最佳实践/原则?我渴望为 java 提供library like factory girl,但由于静态类型,它看起来不太可能。
我目前的想法是此时每个测试类有 1 个 xml 数据集——也许我分享其中一些,也许我不分享。虽然一些测试数据可能会跨数据集重复,但我发现在 3000 个单元/集成测试中维护共享数据集太难了——而且我还有很长的路要走。
希望遵循任何能够使测试表现良好且易于维护的原则。
【问题讨论】:
问题在于性能,但真正关心的似乎是“使它们可维护”。恕我直言,您应该绝对关注可维护性并通过增加更多计算能力来提高性能。 请注意,如果您将多个小型数据集与 DBUnit 一起使用,您可能会遇到随机失败的严重问题。我写了一个blog post explaining why and how to work around it。 如果您渴望 Java 的 Factory Girl,请查看 github.com/mguymon/model-citizen 【参考方案1】:在我之前的一项任务中,我们进行了数百个涉及数据集的集成测试,但不是在 DBUnit 中——测试环境是从头开始编写的,因为它是一家可以负担得起这种东西的大公司。
数据集是分层组织的。被测系统由几个(5-10)个模块组成,测试数据遵循该模式。单元测试脚本如下所示:
include(../../masterDataSet.txt)
include(../moduleDataSet.txt)
# unit-specific test data
someProperty=someData
属性名称被一些我不记得的奇怪工具直接映射到数据库记录。
同样的模式可以应用于 DBUnit 测试。在主数据集中,您可以放置总是需要的记录——比如字典,数据库的初始加载,就好像它要从头开始安装一样。
在模块数据集中,您可以将涵盖大多数测试的测试用例的记录放在一个模块中;我认为您的平均测试不会涉及所有 70 个数据库表,是吗?即使应用程序是单片的,您肯定也必须有一些可以构成模块的功能组。尝试围绕它组织模块级测试数据。
最后,在测试级别,您只需使用此特定测试所需的最少记录数来修改您的测试集。
这种方法具有学习的巨大好处;因为数据文件很少,所以随着时间的推移,您实际上开始记住它们。与其看到数百个大数据集的区别仅在于不明显的细节(您必须在每次返回测试时发现),而是可以轻松判断任意两个数据集的不同之处。
最后谈谈性能。在我的 2.4 GHz 2 核 WinXP 机器上,一个 DBUnit 测试涉及:
删除 14 个表, 创建 14 个表, 插入约100 条记录, 执行测试逻辑,需要 1-3 秒。日志显示前 3 次操作耗时不到一秒,大部分测试时间都被 Spring 消耗了。此逻辑由每个测试执行,以避免测试顺序依赖性。一切都在一个带有嵌入式 Derby 的 VM 中运行,这可能就是它如此之快的原因。
编辑:我认为 DBUnit XML 数据集不支持包含其他测试文件,可以通过对所有集成测试使用基类来克服它,例如:
public class AbstractITest
@Before
public void setUp() throws Exception
//
// drop and recreate tables here if needed; we use
// Spring's SimpleJdbcTemplate executing drop/create SQL
//
IDataSet masterDataSet = new FlatXmlDataSetBuilder().build("file://masterDataSet.xml");
DatabaseOperation.CLEAN_INSERT.execute(dbUnitConnection, dataSet);
public class AbstractModuleITest extends AbstractITest
@Before
public void setUp() throws Exception
super.setUp();
IDataSet moduleDataSet = new FlatXmlDataSetBuilder().build("file://moduleDataSet.xml");
DatabaseOperation.CLEAN_INSERT.execute(dbUnitConnection, moduleDataSet);
public class SomeITest extends AbstractModuleITest
// The "setUp()" routine only here if needed, remember to call super.setUp().
@Test
public void someTest() ...
【讨论】:
我喜欢这个主意。我去看看dbunit是否支持这种东西。 @egervari DBUnit XML 数据集可能不直接支持这个;查看我的编辑。 我非常喜欢你的想法。我认为创建一个充满字典信息的主数据集很棒。但是,我不是 Module 数据集的粉丝。我认为今天很容易根据通用数据将测试分组到模块中,但将来可能会发生变化。如果您不得不更改设计并且不值得受益,那么创建对模块数据集的依赖似乎将是一件非常头疼的事情。我可以看到它会在哪里工作。我想这真的取决于你的数据模型。【参考方案2】:Junit in Action 2e 中的建议实际上是不要创建太多的数据集(例如每个测试类一个),但要足够被认为是可维护的。除了少数例外情况,我发现大多数单元测试可以使用主数据集,集成测试可以使用单个数据集。限制 ExpectedDataSets 的使用也是一种选择。
此外,我将Unitils 与 dbunit 结合使用以简化测试数据的一些设置和加载,因此您可能需要在适当的时候考虑它。
【讨论】:
如果这是推荐的话,我认为这本书是错误的。当您有一个包含 70 个表的数据库,并且您在标志上有这么多不同的布尔字段时,需要测试大量的搜索条件,等等……更改 1 行可能会导致大量测试中断。这很糟糕,我认为这是浪费时间。也许在代码中使用构建器模式,然后使用级联将它们保存到数据库中就是答案。我不确定。 澄清:在大多数单元测试中使用单个主数据集是我在特定情况下所做的选择。本书只建议您只维护您准备维护的数据集,因此您可以考虑一个不太严格的比率,而不是每个类/表 1 个。 我目前的想法是它不会是 1:1,但至少 50% 的测试会是 1:1,其余的会共享它们。随着我的应用程序变得越来越复杂,我需要减少与数据集的耦合。我目前有 5 个数据集构建 1 个数据库 - 每个测试使用 1 到 5 个数据集。它旨在充当 1 个数据库。我认为这是一个错误。它让我走上了测试依赖地狱的道路。 所以目前您对 3000 个不同的测试使用的唯一数据集不超过 5 个?绝对不建议这样做,因为数据集应尽可能地特定于测试(在合理和可维护的范围内)。您可以继续将它们用于某些集成测试,但对于单元测试,我会尝试使用特定于表的数据集(即使它将是 70 个左右) 我想我正在寻找一些已经在大型项目中尝试并成功的好的原则。比如什么时候制作数据集,放在哪里,它应该包含多少数据等等。以上是关于dbunit 性能最佳实践的主要内容,如果未能解决你的问题,请参考以下文章