首页 > 解决方案 > Spring中单元测试如何插入记录(无删除方法)

问题描述

我有使用 Spring 的 DAOjdbcTemplate和创建读取更新(无删除)操作。

创建方法具有 ID 参数,该参数是表中的唯一键。

除了模拟 DAO,我如何才能在不违反约束的情况下实际测试创建?

使用随机 ID 有时仍然会失败

我应该覆盖 setAutoCommit 以避免添加记录吗?它仍然认为是有效的单元测试吗?

我必须事先在 SQL 中删除数据库中的记录,还是这种类型的测试有 spring 选项?

还是我应该将其视为集成测试而不是单元测试?

编辑

我正在使用 Oracle,我不能使用序列来为 ID 创建值

我们在生产中存在一些数据源(不用于测试)

标签: javaspringunit-testingdaojdbctemplate

解决方案


这实际上取决于这种测试的目的是什么,并不是所有的测试都是这方面的“单元测试”。

例如,如果目标是测试封装业务逻辑的“服务”,但从该服务中,有时会调用 DAO,那么最好的方法可能就是按照您的建议模拟 DAO。在这种情况下,DAO 显然不会被这个测试覆盖,但服务会。

如果目的是测试 SQL 语句(并且我假设 DAO 只包含 SQL 语句+可能将它们转换为域对象),那么模拟不是一种选择。

在这种情况下,测试应该包括对某种数据库的调用,但在这种情况下,它不再被称为单元测试(单元测试是运行非常快并且只在内存中,没有 DB,没有 I/O,等)我将其称为集成测试(正如您也建议的那样),但不同的人可能对这种测试有不同的名称。

在实践中,我们需要两种测试,因为它们测试不同的东西

那么,如何测试呢?

首先应该做出决定,应该使用哪个数据库,这里有3种方法:

  1. 使用真实的数据库运行,在用户之间共享,测试假定它是预先安装的
  2. 使用内存数据库运行
  3. 测试套件运行时运行DB的DB docker镜像,之后销毁

虽然关于哪种方法更好的讨论本身非常有趣,但它超出了 IMO 这个问题的范围,每个选择都有其含义。

一旦你完成了这个决定,你应该决定如何从代码中使用这个数据库。

通常弹簧测试使用以下模式:

  1. 测试前开启交易
  2. 运行测试(更改数据,甚至更改架构 - 如果需要,添加列、表)。做断言
  3. 无论测试结果如何,都回滚事务,使数据与测试前一样

因此,如果您对所有测试都遵循这种方法,它们将以“空”数据状态开始,这样就不会违反约束。这也有效地解决了“删除记录”问题,因为在事务处理时无论如何都会删除数据被回滚。

现在关于删除事务外的记录。

一个明显的方法是从测试中(在 DAO 之外)执行删除的 sql,以便 DAO(生产代码不会被更改)

您可以将 DataSource/JDBCTemplate 直接注入到测试中(Spring 测试完全支持这一点)并从那里调用所需的 SQL


推荐阅读