3

发现自己针对数据库调用编写单元测试是很常见的,而且我总是遇到同样的问题:如何验证是否将一个好的查询发送到数据库?

例如,我有这个类,它将以下列形式向数据库发送最终更新:

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?

我看到很多项目创建带有少量数据的小型嵌入式数据库来测试处理数据库的类,但我想编写一个更纯粹的单元测试替代方案(如果我可以称之为)

4

3 回答 3

2

我认为没有一个很好的替代方法来测试真实的数据库(即使它是嵌入式的等)。目前,您正在测试您的 SQL 在语法上是否有效,但它是否真的可以工作。例如,您知道它是否会违反约束等...

模拟等一切都很好,但是在某些阶段您必须针对数据库进行测试。我会确保您尽可能不对数据库进行测试,然后硬着头皮围绕一个小型数据库构建测试(具有适当的回滚/重建等),以实际确认正确的数据库功能。

于 2013-02-19T00:01:41.883 回答
1

我恳请您重新考虑这些测试的好处,因为

  • 它正在验证实现而不是行为
  • 当您将来更改 SQL 查询时(或者有人只是错误地添加了一个无害的空间),即使您保留了行为,您也会有一个失败的测试。

对于最终的 DataAccessLayer,我建议编写一个集成测试。一个与真实但最小的数据库运行的数据库。当然,这些测试会很慢,但它们提供的信心是值得的。

因此,针对 GetCustomers() 编写测试并验证返回的 DTO 是否包含正确的数据,而不是验证您发出的 SQL 查询是 X。

于 2013-02-19T05:56:33.467 回答
1

不要断言你的 sql。这是毫无意义。您最终会将传递的 sql 字符串与另一个字符串(也由您创建,因此没有验证)进行比较,或者您必须实现自己的数据库。而是只使用现有的。检查是查询返回正确的数据或正确更改数据库中的数据。使用 dbunit 或类似的东西。

于 2013-02-19T17:30:52.457 回答