发现自己针对数据库调用编写单元测试是很常见的,而且我总是遇到同样的问题:如何验证是否将一个好的查询发送到数据库?
例如,我有这个类,它将以下列形式向数据库发送最终更新:
update credential set password_hash = ?, password_crypt = ?, password_plain = ? where id = ?
(这是一个密码迁移工具,请不要介意该password_plain
字段的安全问题)
为这个类编写测试类,我已经模拟了数据库访问类(在这种情况下我使用的是 Spring JDBCTemplate)并捕获了发出的 sql。获得 sql 后,我会进行以下检查:
String space = "\\s+";
String optSpace = "\\s*";
String something = ".+";
String optSomething = ".*";
sql = sql.toLowerCase();
assertTrue(sql.matches(optSpace + "update" + space + "credential" + space + "set" + space + something));
assertTrue(sql.matches(something + space + "set" + space + optSomething + "password_hash" + optSpace + "=" + optSpace + "\\?" + something + "where" + something));
assertTrue(sql.matches(something + space + "set" + space + optSomething + "password_crypt" + optSpace + "=" + optSpace + "\\?" + something + "where" + something));
assertTrue(sql.matches(something + space + "set" + space + optSomething + "password_plain" + optSpace + "=" + optSpace + "\\?" + something + "where" + something));
assertTrue(sql.matches(something + space + "where" + space + optSomething + "id" + optSpace + "=" + optSpace + "\\?" + optSomething));
通过这些检查,我确实在验证发布的 SQL 是否包含更新的最重要部分,例如:
- 正在更新正确的表
- 所有 3 个字段都被更新为作为参数传递的值
- 正在语句
id
中使用where
,其值作为参数
我可以简单地验证发出的查询是否正是上面的预期查询,但这会使测试对未来的更改过于限制,并且如果查询的任何部分被更改,即使更新保持正确,也会强制失败。因为我认为编写的测试主要用于将来(当您更改软件并且需要更多保证时)而不是现在,所以这个选项会使测试有点无用。
好吧,最后,我声明我的问题:我们有哪些更好的选择来验证已发布的 SQL?
我看到很多项目创建带有少量数据的小型嵌入式数据库来测试处理数据库的类,但我想编写一个更纯粹的单元测试替代方案(如果我可以称之为)