我目前正在使用Java 17、Dropwizard和JUnit 5进行一个Java项目,我专注于改进我的单元测试和采用测试驱动开发(TDD)实践.我的应用程序通过DAO接口与数据库交互,我正在探索测试这些交互的最佳方法,特别是对于执行诸如将数据插入数据库但不返回值的操作的方法.

考虑到这些方法的性质,我考虑了两种主要的测试方法:

  1. 使用假实现:创建我的DAO接口的假实现,以模拟内存中的数据库操作
  2. 使用内存数据库:使用内存数据库(如H2)在受控环境中执行真实的数据库操作.

我知道假实现通过避免设置真实数据库连接的开销来提供速度和简单性,使它们非常适合单元测试.另一方面,内存数据库提供了一个更真实的测试环境,这似乎有利于集成测试,以确保我的SQL查询和事务按预期的方式运行.

我的问题:

  1. 在TDD环境中,考虑到测试中速度和真实性之间的平衡,对于不返回值的测试方法,您会推荐哪种方法?
  2. 是否有特定的设想方案或项目阶段,其中一种方法明显优于另一种方法?

我的目标是一种测试策略,它不仅确保可靠性和可维护性,而且与TDD的最佳实践相一致.您可以分享的任何见解、经验或建议都将不胜感激.

谢谢你!

推荐答案

在TDD环境中,考虑到测试中速度和真实性之间的平衡,对于不返回值的测试方法,您会推荐哪种方法?

测试行为,而不是方法.正如你提到的,你想要的行为是你可以成功地编写一个项目,而你测试这种行为的方式是你try 并阅读项目.这可能看起来像

@Test
public void it_can_save_an_item() {
    MyDao dao = new MyDao();
    Item item = new Item("foo", "bar");

    dao.save(item);

    List<Item> savedItems = dao.findAll();
    assertEquals(item, savedItems.get(0));
}

就我个人而言,我不使用内存数据库,原因与其他人在上面提到的相同.

我倾向于采用的方法是使用一个假的,并集成测试真正的实现,使用契约来确保两个抽象版本的行为是相同的.例如,参见https://quii.gitbook.io/learn-go-with-tests/testing-fundamentals/working-without-mocks个关于假货和合约的例子(Go语言中有例子,但建议实际上与语言无关).

这里我的观点来自于从外到内(或"伦敦风格")TDD,在这种情况下,系统的设计从验收测试中脱颖而出.也就是说,您正在弄清楚您需要什么抽象,以及它们应该如何看起来,而伪造是一种相当轻量级的方式来帮助您(但还有其他原因—参见上面的链接).

我想,如果您正在做更多的由内而外("芝加哥风格"),并且正在对需要DAO的组件进行单元测试,您仍然希望获得同样的信心——您可以使用一个运行得像真实的DAO版本来测试您的组件.

Java相关问答推荐

在Spring Boot中测试时出现SQL语法错误

Annotation @ Memphier无法正常工作,并表示:class需要一个bean,但找到了2个bean:

@ EnableRouting注释在Kotlin项目中不工作

springboot start loge change

无法处理批处理侦听器中的反序列化异常

如何以干净的方式访问深度嵌套的对象S属性?

如何在运行时动态创建表(使用Java、JPA、SprringBoot)

第二次按下按钮后,我需要将按钮恢复到其原始状态,以便它可以再次工作

OpenGL ES 3.0-纹理黑色

try 判断可选参数是否为空时出现空类型安全警告

MimeMessage emlMessage=new MimeMessage(Session,emlInputStream);抛出InvocationTargetException

搜索列表返回多个频道

try 将JSON字符串响应从API转换为映射字符串、对象>;时出错

支持MySQL 5.6的最新Hibernate版本

Kotlin Val是否提供了与Java最终版相同的可见性保证?

如何在JavaFX循环中完美地制作一个AudioClip/MediaPlayer?

从映射列表中检索所有键

从12小时开始的日期模式

如何在SWT菜单项文本中保留@字符

为什么Instant没有从UTC转换为PostgreSQL的时区?