我正在考虑制作一个新的,轻量级的数据库人口框架。我绝对讨厌dbunit。在我这样做之前,我想知道是否有人已经这样做了。
我不喜欢dbunit:
1)不推荐使用最简单的写入和开始格式。他们希望您使用膨胀的格式。有些甚至需要xml架构。是的,无论如何。
2)它们不按您编写的顺序填充行,但在顺序表中是在xml文件中定义的。这非常糟糕,因为您无法以外键约束不会导致问题的方式对数据进行排序。这只会迫使你彻底解决它们的麻烦。
这也会浪费时间并使你的junit基类膨胀,以包含禁用外键约束的代码。您可能必须测试数据库类型(hsqldb等)并以特定于数据库的方式禁用它们。这很糟糕。
如果dbunit有助于自动禁用外键约束作为其框架的一部分,但它们不会这样做。他们确实跟踪方言......所以为什么不使用它们呢?最终,所有这一切都迫使程序员浪费时间而不是快速起床和测试。
3)XML写起来很痛苦。我不需要多说这个。他们也提供了很多方法,我认为这只会使问题复杂化。只需提供一个非常可靠的方法并完成它。
4)当您的数据变得庞大时,跟踪ID及其一致/正确的关系是一种巨大的痛苦。
另外,如果你一个月没有在项目上工作,你怎么记得user_id 1是管理员,user_id 2是业务用户,user_id 3是工程师而user_id 4是别的什么?回去检查这是浪费更多时间。除了任意数字之外,应该有一种有意义的方法来检索它。
5)这很慢。我发现除非使用hsqldb,否则它会非常缓慢。它不一定是。还有很多方法可以搞乱其配置,因为“开箱即用”并不容易。有一个驼峰,你必须通过它来使其正常工作。所有这一切都鼓励人们不要使用它,或者在他们开始使用它时感到生气。
6)有些值往往会重复很多,比如日期。指定默认值,甚至让框架自动设置默认值是很好的,即使没有告诉它将默认值放在那里。这样您就可以使用所需的值创建对象,并将其余部分保留。如果不需要,这肯定会指定列的每个角落和裂缝。
7)最令人烦恼的可能是第一个条目必须包含所有值 - 甚至是空占位符 - 或者将来的行不会选择您实际指定的列。
DBunit没有将[NULL]转换为实际空值的合理默认值。您必须手动添加它。告诉我,谁没有用dbunit做到这一点?每个人都有。它应该不是这样的!
这意味着如果你有一个多态对象,你必须声明第一行中每个子类的连接表的所有外键,即使它们是null。如果为所有子类模式执行表,则仍必须指定第一行上的所有字段。这太糟糕了。
有什么东西让我满意,或者我应该成为更好的数据库测试框架的下一个框架开发人员?
答案 0 :(得分:96)
我不知道DbUnit的任何替代品,@Joe提到的工具都不在我的眼里:
话虽这么说,我个人已经成功地在小型和大型项目上多次使用过DbUnit,我发现它非常实用,特别是在使用Unitils及其DbUnit模块时。这并不意味着它是完美的,无法改进,但使用不错的工具(定制或类似Unitils),使用它是一种不错的体验。
让我回答你的一些观点:
1)不推荐使用最简单的写入和开始格式。他们希望您使用膨胀的格式。有些甚至需要xml架构。是的,无论如何。
DbUnit支持平面或结构化XML,XLS,CSV。你想用什么革命性的格式?顺便说一句,使用XML时,DTD或模式不是必需的。但是它为你提供了诸如验证和自动完成之类的好东西,那有多糟糕? Unitils可以轻松为您生成,请参阅Generate an XSD or DTD of the database structure。
如果dbunit有助于自动禁用外键约束作为其框架的一部分,但它们不会这样做。他们确实跟踪方言......所以为什么不使用它们呢?最终,所有这一切都迫使程序员浪费时间而不是快速起床和测试。
他们正在等你的补丁。
同时,Unitils提供透明处理约束的支持,请参阅Disabling constraints and updating sequences。
3)XML写起来很痛苦。我不需要多说这个。他们也提供了很多方法,我认为这只会使问题复杂化。只需提供一个非常可靠的方法并完成它。
我认为疼痛是主观的但我并不觉得痛苦,特别是在使用模式和自动完成时。你建议的银弹是什么?
4)当您的数据变得庞大时,跟踪ID及其一致/正确的关系是一种巨大的痛苦。
保持小,这是一个知道best practice。你反对一个已知的最佳实践,然后抱怨...
另外,如果你一个月没有在项目上工作,你怎么记得user_id 1是管理员,user_id 2是业务用户,user_id 3是工程师而user_id 4是别的什么?回去检查这是浪费更多时间。除了任意数字之外,应该有一种有意义的方法来检索它。
是的,任务切换会适得其反。但是由于你正在使用低级数据,你必须知道它们是如何表示的,除非你当然使用更高级别的API(但这不是DbUnit的目的),否则没有神奇的解决方案。
5)这很慢。我发现除非使用hsqldb,否则它会非常缓慢。它不一定是。还有很多方法可以搞乱其配置,因为“开箱即用”并不容易。有一个驼峰,你必须通过它来使其正常工作。所有这一切都鼓励人们不要使用它,或者在他们开始使用它时感到生气。
这是数据库和JDBC固有的,而不是DbUnit。如果你想让事情尽可能快地使用像H2这样的快速数据库(如果你有一种更好的不可知的做事方式,我很乐意了解它。)
6)最令人讨厌的事情可能是第一个条目必须包含所有值 - 甚至是空占位符 - 或者将来的行不会选择您实际指定的列。
在使用Unitils - Home - JavaPolis 2008或Unit testing: unitils & dbmaintain等演示文稿中提到的单位时不会。
有什么东西让我满意,或者我应该成为更好的数据库测试框架的下一个框架开发人员?
如果您认为自己可以做得更好,可以为现有解决方案做出贡献。如果那是不可能的,如果你认为你可以创建杀手数据库测试框架,我能说什么,做到这一点。但不要忘记,咆哮很容易,使用自己的解决方案提出解决方案就不那么了。
答案 1 :(得分:26)
作为DbUnit开发者,我很感激批评,我必须部分同意你的看法。我们目前正在开始设计下一个DbUnit主要版本,我希望邀请您参与讨论和开发。
我不会回答你的观点,因为你的问题与DbUnit没有关系,而是与DbUnit的替代方案有关。无论如何,我只是想突出你的观点7是完全错误的:你不需要再指定第一行的所有列,该功能称为列感应。我不会告诉你为什么默认情况下没有启用它,因为你确实很聪明,可以自己理解它。
我会对scaladbtest进行深入研究,希望我们能够整合他们的想法。
答案 2 :(得分:16)
面对使用DBUnit的类似问题,我发现了这一点:http://dbsetup.ninja-squad.com/index.html可能会解决问题。例如,不是在单独的文件中表示测试数据,而是所有DB内容都包含在java类本身中。
答案 3 :(得分:4)
如果您使用Spring Framework(或者不介意至少使用它进行测试),那么Spring DBUnit目前是我所知道和使用的普通DBUnit的最佳(维护)替代方案。引用他们的网站:
Spring DBUnit提供了Spring测试之间的集成 框架和流行的DBUnit项目。它允许您设置和 使用简单注释以及检查来拆除数据库表 测试完成后预期的表格内容。
Spring DBUnit似乎是用于数据库单元测试的“有点官方”的Spring解决方案(使用DBUnit);至少图书馆的作者/维护者Phil Webb正在SpringSource / Pivotal工作。
答案 4 :(得分:3)
我使用DBUnit,用几个包装器来平滑粗糙的边缘。一个可以补充或重叠功能的好工具是Jailer。它可以从参考数据库中提取数据子集,并将其存储为兼容DBUnit的XML文件,或者作为“拓扑排序的DML文件”存储,这些文件遵循外键约束。
答案 5 :(得分:2)
你提出了很好的观点。
在过去的几年里,我一直在为很多门户网站工作,主要是使用PHP,但偶尔也会使用一些Java。
和你一样,经过这么多年后,我不知道框架和单元测试开发人员似乎没有意识到在过去十年中存储处理有多大变化。
仅将create / insert / truncate语句发送到某个数据库是不够的!
如果您在大规模运营,最终会采用各种存储后端,分层组织以快速推送热门内容。此外,在数据库方面还存在数据分区问题。如果您没有适当的外键抽象,那么当您的存储设置发生变化时,您肯定会疯狂。虽然我们正处于这种状态:通过外键优先级进行夹具排序存在许多缺陷,我还没有看到DBUnit
的真正解决方案。
无论如何,重点是只有一个基本的数据库存储来进行单元测试对于复杂的存储设置是不够的,因为它们经常无法在现场环境中重现问题并且难以维护。
不想听起来像一个粉丝:一个好的地方是ruby on rails
。
这有一个持久的模型概念,人们似乎实际上已经考虑了一些。如果您正在处理PHP
,Symfony
就是您要去的地方。它通过默认包含Doctrine
来限制,同样也是以数据库为中心的,但它具有干净的界面和极大的可扩展性,并完全复制了rails fixture系统。专业上我现在需要坚持自制解决方案,但它们工作正常。
答案 6 :(得分:2)
答案 7 :(得分:1)
这里有一些简短的清单,列出了一些我特别喜欢或有趣的工具(除了DBunit)。至少他们可能会提供一些灵感:
请注意,就范围或功能集而言,这些都不是DBunit的真正竞争对手。但是,有一些有趣的想法可能值得一看。祝你好运!
答案 8 :(得分:1)
我们正在编写Daleq作为DbUnit的包装来解决一些上述问题。它允许在单元测试中填充数据库,而不是依赖于编辑XML文件。
答案 9 :(得分:1)
我也遇到过与DBUnit类似的问题。特别是用于填充本地开发数据和从真实数据库导出数据。我遇到了几种情况,它会导出一个无法导入的数据集。
这激励我为它编写一个新的库:https://github.com/jeffskj/phonydata
这使用了一个groovy DSL来定义数据集,这些数据集可以非常紧凑地表示数据,并且可以像生成随机数据那样做很酷的事情,因为它只是简单的代码。
答案 10 :(得分:1)
另一种投票方式是将DBUnit与现代库一起包装以提高可用性和简洁性。我的选择是database-rider,这使DBUnit易于使用,甚至支持JUnit 5,如以下示例所示:
@RunWith(JUnitPlatform.class)
@ExtendWith(DBUnitExtension.class)
@DBUnit(cacheConnection = true, cacheTableNames = true)
class TestInstrumentQueryService {
private ConnectionHolder connHolder = () -> EntityManagerProvider.instance("my-jta-unit").connection();
@DBRider
@DataSet("datasets/instrumentIds.yml")
void testFindInstrumentById() {
InstrumentQueryService iqs = new InstrumentQueryService(EntityManagerProvider.em());
Instrument instr = iqs.findInstrumentById(InstrumentIdType.TICKER_BBG, "AAPL");
assertEquals(100, instr.getId());
}
}
请注意,这如何允许无缝地利用(精简)YAML测试数据集(YAML不是XML,尽管我认为DBUnit实际上是本地支持的)。
答案 11 :(得分:0)
可以找到使用 Spring 配置和 Specs2 测试的替代方法here
答案 12 :(得分:0)
我刚刚通过github发布了一个名为pedal-loader的groovy DSL架构。文档here。
它允许您直接使用JPA实体级抽象。由于它是一个groovy脚本,您可以使用所有groovy构造。
要将行插入由名为Student的JPA实体支持的表中,使用名为id,name和grade的字段(不是数据库列,但是映射字段),您可以执行以下操作:
allStudents = table(Student, ['id', 'name', 'grade']) {
row 1, 'Joe', Grade.A
rowOfInterest = row 2, 'John', Grade.B
}
Grade是映射到数据库列的Student类中的枚举(可能使用JPA 2.1 @Convert批注)。 allStudents是一个包含行的列表,rowOfInterest是对特定行的引用。这些属性(allStudents和rowOfInterest)可用于您的单元测试。
答案 13 :(得分:0)
DBUnit的情况确实有时令人沮丧。部分问题是通过append()与Marc Philipp解决的,特别是如果您将其与dbunit-datasetbuilder结合起来,这是一个非常早期的阶段。您可以在validator处看到它。
免责声明:所有引用的github资源均由我维护。