我正在使用 SimpleTest,一个基于 PHP 的单元测试框架。我正在测试将处理从数据库存储和检索网站评论的新代码。我不知道如何构建项目来测试数据库访问代码。
我正在寻找有关在 PHP 应用程序中测试数据库代码的最佳实践的任何建议。例子真的很棒。进一步阅读的网站很棒。
非常感谢你。:)
我正在使用 SimpleTest,一个基于 PHP 的单元测试框架。我正在测试将处理从数据库存储和检索网站评论的新代码。我不知道如何构建项目来测试数据库访问代码。
我正在寻找有关在 PHP 应用程序中测试数据库代码的最佳实践的任何建议。例子真的很棒。进一步阅读的网站很棒。
非常感谢你。:)
这是一个老问题,但我想我会添加一些我们在这方面的具体经验。
其他海报在技术上是正确的,这是一种集成测试形式,但从我所在的位置来看,MySQL 中的逻辑通常太多,无法在单元测试中剔除。如果您像我们一样拥有严重依赖 MySQL 的大型复杂服务(通常每个服务有多个表),那么拥有一个包含测试查询逻辑的强大测试框架非常方便。我们在单元测试中模拟了很多依赖项,但没有模拟 MySQL。
我们有一组包装 simpletest 的类来提供这个功能。它的工作原理是这样的:
tests/etc/schemas/table.sql
。它包含模式数据以及测试期望找到的所有预设数据的插入。Test_DbCase
类,该类提供构建表的功能。loadTables('foo', 'bar')
setUp 方法执行 和 中的 sqlfoo.sql
命令bar.sql
。我们拥有的另一个工具是 bash 脚本,它可以更轻松地创建table.sql
文件。这真的很方便,因为否则我们将手动编写 SQL - 您可以获取一组现有的表,在 MySQL 中设置所有数据,然后将其导出以创建测试文件。
这对我们来说非常有效,尽管我们最终不得不自己推出很多。
我有一个本地数据库,专门用于使用已知名称和数据库用户名/密码进行单元测试。单元测试被硬编码到该位置,但不同的开发人员可以根据需要覆盖这些变量。
然后在每次测试你TRUNCATE
每张桌子之前。这比删除/创建表或数据库本身要快得多。
注意:不要在测试后截断!这样,如果测试失败,您将获得数据库的当前状态,这通常有助于诊断问题。
您可能希望允许 PHP 创建并向临时表/数据库提供数据并在该表/数据库上进行测试。然后您不必手动重置数据库。大多数框架都有数据库操作库以使其更容易。前端可能需要一些时间,但稍后进行更改时可以让您更快地进行测试。
When testing database code, it's good to always have the same database as the starting point. Especially if you do unit-testing (which I assume is the case here). One of the ways is to truncate all tables as Jason suggested, but I prefer to have some starting data in it. You know, you always need to have some 'default' data that is present in each database.
Also, some tests only make sense with full database. So, create a special instance of database for those tests. I have about 3 or 4 different databases that I plug-in (just copy the files in) before running some tests. Having the same starting point each time ensures repeatability.
So, just prepare a few database states that are good 'starting points' and back them up. Before running each set of tests, restore appropriate database, and then run it.
如果您真的想针对数据库进行测试,我建议您在每次测试之前导入数据/创建表。这样,您的数据库就从每次测试的已知状态开始。由于这相当耗费性能,因此您可以setUp
在tearDown
. MySql(可能是您正在使用的 RDBMS)不支持嵌套事务,因此如果被测代码使用事务,您可能会遇到麻烦。您可以使用savepoints解决此问题。测试前设置保存点,测试后回滚到保存点。
我仍然坚持认为,如果你需要很多,你应该考虑你的测试试图告诉你一些事情的可能性..
我鼓励您不要尝试使用 SimpleTest 测试数据库访问代码。
相反,使用例如 Selenium 为您的应用程序创建一个功能测试:当您从数据库的已知状态开始时记录一个测试用例;然后添加评论并检查(使用 Selenium 的断言)内容确实存在。
这样: - 更易于设置和维护 - 您不仅可以验证 DB 层,还可以验证表示层
也就是说,如果您的数据库中有存储过程,请使用 SimpleTest - 我自己已经成功完成了。基本上,创建从已知 DB 状态开始的 SimpleTest,然后执行一些 INSERTS/UPDATES,然后运行存储的 proc 并确保 DB 的状态是您所期望的。
我认为您应该使用 ORM,并为此编写一些集成测试。如果集成测试显示它在实际环境下可以完美运行,那么只有在更改环境(数据库、php 版本、平台等)时才需要再次测试它。之后,您可以模拟 ORM 对象,而无需连接到数据库。
所以我认为这是最好的方法,但是如果您不想使用 ORM,那么您可以创建一个测试数据库并模拟数据库连接(PDO)对象。在这种情况下,您可以在 testCases 的 setUp 和 tearDown 部分创建和删除测试表。重要的是这些是集成测试,而不是单元测试,所以你不需要总是运行它们,只有在 PHP 和 SQL 服务器之间发生变化时才需要运行它们。在使用集成测试测试数据访问对象后,您必须在单元测试中模拟它们。
对数据库进行测试通常表明测试不好,这可能是由于被测代码中缺乏封装。您应该尽量将与数据库交互的代码与其余代码隔离开来,让交互层保持简单,以便您可以通过一些非常基本的测试来摆脱困境。
换句话说; 处理注释的代码不应与处理数据库交互的代码相同。例如,您可以编写一个通用表模块,您的评论模型使用它来访问数据库。您仍然需要测试 table 模块,但这应该与注释代码隔离开来。