使用 DBUnit/Junit 测试我的 REPOSITORY 层,我应该手动构建方案还是自动构建它?有什么好处?

testing my REPOSITORY layer with DBUnit/Junit, should I manually build scheme or automate it? what's the advantages?

我正在考虑如何为基于 java 的存储库设计单元测试并遇到设计问题: 假设我有一个 Consumer table,其中包含与我的消费者相关的数据: { ID, 姓名, Phone } 我的 ConsumerRepository 扩展了 BaseRepository,后者扩展了 JPA 存储库并支持 findByPhone、findByName、findAll 查询和保存选项。

我正在使用 H2 in-memo DB 和 DBUnit 进行这些测试,所有配置和 运行 正在考虑这个:

  1. 将数据启动到我的内存数据库时,我是否应该使用 ConsumerTestData.xml (DBUnit) 配置数据并为每个测试手动添加消费者数据,例如:

    <dataset>
    <CONSUMER CONSUMER_ID="1" FIRST_NAME="Elvis" LAST_NAME="Presley" PHONE="+972123456789" EMAIL="elvis@isep.com" CREATION_DATE="2017-08-29"/>
    <CONSUMER CONSUMER_ID="2" FIRST_NAME="Bob" LAST_NAME="Dylan" PHONE="+972123456780" EMAIL="bob@isep.com" CREATION_DATE="2017-08-29"/>
    <CONSUMER CONSUMER_ID="3" FIRST_NAME="Lady" LAST_NAME="Gaga" PHONE="+972123456781" EMAIL="gaga@isep.com" CREATION_DATE="2017-08-29"/>
    </dataset>
    

还是我应该自动化它? 例如:

@Test
public void findByPhone(){
    ConsumerEntity consumerEntity = ConsumerUtil.createRandomConsumer();
    ConsumerEntity savedConsumerEntity = consumerRepository.save(consumerEntity);
    assertThat(consumerRepository.findByPhone(savedConsumerEntity.getPhone()).isEqualTo(savedConsumerEntity.getPhone());
}

虽然我的 createRandomConsumer 生成随机数据。

优点: 我认为自动化会更加通用和方便,就好像 ConsumerEntity 可能会更改或接下来有任何代码更改一样 - 我将不必更改我的 .xml 文件,只需能够向 TestEntity 函数添加内容。 缺点: 如果 DB 方案中包含任何约束,则创建新对象并保存到 in-memo DB 可能会更加困难。

  1. 我应该使用 DBUnit 吗?如果自动化 - 我为什么要使用 DBUnit?仅使用 JUnit 是否更好(每次测试后回滚数据并像上面的示例一样自动添加测试所需的数据?)

  2. 如果为此选择使用 DBUnit - 并手动添加 - 这样的优点是什么?为什么它比使用带有 Spring 的简单 JUnit 更好?

谢谢!

1) 仅使用 随机或运行时生成的夹具进行测试是不合适的。
它不会使测试可重现,因此如果失败会使它们更难调试,并且它也不会使测试记录代码。

此外,具有显式数据的装置减少了数据生成可能引入的副作用。
您确定生成的数据符合要求吗?
您确定您的生成工具按预期工作吗?
你测试过了吗?
所以对于... 找到所需的边缘情况很好,但发明不需要的边缘情况意味着您的测试将改变您的要求。
而你不想要那个。
如果你确定了所有的具体案例,你想生成一些数据,因为你认为你有太多的组合(例如十几个输入案例),当然根据需求生成夹具是很好的。
否则,不要这样做,因为它看起来是一个开销。

2) DBUnit,这是一个选择。
在我使用它之前。现在,我停了下来。它有一些优点,但很笨重,而且 maintenance/improvements 很轻。
最近,我尝试了来自 JBNizet(SO 成员)的 DbSetup
API 从 Java 代码向数据库中插入数据相当不错:简单直接可用。

例如在DB中插入数据,一个Operation可以定义为:

Operation consumerInserts = sequenceOf(
    insertInto("CONSUMER")
        .columns("ID", "FIRST_NAME", "LAST_NAME")
        .values(1, "Elvis", "Presley")
        .values(2, "Lady", "Gaga")
        .values(3, "Bob", "Dylan")
        .build();
)

3) 所以,没什么可补充的。

你好像在问2个问题:是否使用DBUnit和是否使用随机化。

至于DBUnit

  • 它增加了额外的步骤和额外的维护成本。如果您已经有了保存实体的代码(通过 XxxRepository),那么就没有理由再引入额外的工具了。
  • 这不仅适用于 DBUnit,也适用于任何复制现有持久性逻辑的工具。
  • 相反,您可以只创建一个对象实例,填写所有字段并保存在存储库中。这使重构变得更加容易。

至于测试随机化

  • 我觉得你的测试看起来很不错。通过随机化,您可以用更少的测试覆盖更多的案例,找到您自己想不到的棘手案例,轻松隔离您的测试(例如,生成唯一的用户名而不是在某处跟踪它们)等。
  • 根据缺点:良好的随机化(以及一般的良好测试)需要对 OOP 有很好的掌握,所以当项目变大时,并不是每个人都能轻松使用它。测试也时不时地开始失败,因为它们是仓促编写的,并没有考虑到每一种可能性。要捕获此类情况,您应该 运行 在本地多次进行测试(有时人们会忘记)。好消息:IntelliJ 可以为 JUnit 重复测试 N 次(对于 TestNG 有注释)。

一般来说,在编写随机测试时应该多考虑。但如果编写得当,它们可以提供更好的覆盖范围和更低的维护开销。如果您对不同的随机化技术感兴趣,check this out.