【问题标题】:Mock my database for all unit tests in PHPUnit为 PHPUnit 中的所有单元测试模拟我的数据库
【发布时间】:2011-09-07 01:14:58
【问题描述】:

我最近刚刚开始研究使用 PHPUnit 进行单元测试,并且想知道是否可以为我的所有测试模拟整个数据库。我的模型类(封装以提供 ActiveRecord 实现的 Table Row 对象)植根于数据库,并且一些模型具有许多级别的其他模型类,因此模拟所有这些似乎在后端会很痛苦。

是否可以让 PHPUnit 使用 CSV 文件中的数据充当我的数据库并针对那里的数据运行我的测试,而无需接触我的 DAO?我已经阅读了 PHPUnit 中关于数据库测试的部分,但我不确定这是我想要的,因为我不想测试数据库或与数据库交互的代码,更重要的是我的模型类是与数据库非常相关,一直模拟事物会很痛苦。如果我可以给它一个 CSV 文件作为我的数据库,那么我可以将我的数据放入 CSV 文件并照常进行。

不确定我是否在说清楚,所以请要求澄清。如果有可能实现这一点,那就太棒了。如果没有这个单元测试,这个野兽可能不实用,但我真的想在项目中引入单元测试。

谢谢

齐亚德

【问题讨论】:

  • 我发现在测试使用 DAO 的类时最好模拟 DAO 本身。只要您可以手动构建模型实例以从模拟 DAO 查询方法返回,就可以了。

标签: unit-testing mocking phpunit


【解决方案1】:

您也许可以创建数据库的副本,然后在您的测试引导程序中简单地连接到该副本?

我也有同样的情况,这是我目前正在研究的选项...并不完美,但至少它可以让第一次测试工作

【讨论】:

  • 是的,我同意并完全与“但至少它使第一个测试工作”有关:) 但说真的,我认为这是要走的路,以及戴夫建议的回滚。
【解决方案2】:

如果使用您的数据库但不提交更改呢?还是在测试运行后回滚?我们使用生产站点的副本作为单独服务器上的测试环境,并在那里进行所有测试。

【讨论】:

  • 是的,在提交了问题后,我开始想,也许我从错误的角度来处理这个问题。我应该使用一个 real 数据库,但它只是为了进行测试而设置的。我喜欢你在测试后回滚的想法。我会看看我能不能让它工作。我还是想听听其他单元测试人员怎么说。
【解决方案3】:

在我看来,使用 DBUnit 测试依赖于 DB 的代码有几个优点。我同意,这些可能适用于所有人,也可能不适用于所有人。我自己直到最近才使用 DBUnit,因为我发现它对于我参与的小项目来说太过分了。

使用 DBUnit 可以将您的测试与数据库分离。您的被测系统不应依赖数据库服务器来运行,您需要尽可能多的隔离。这通常没什么大不了的,因为很多人使用单元测试进行集成测试,为此您更愿意使用尽可能匹配您的生产环境的数据库设置。

DBUnit 受欢迎的另一个原因是它在编写测试时节省了时间。 编写测试不是我喜欢做的编码的一部分,并且尽可能使用模拟可以节省大量时间。当然,创建数据库的副本很容易,但是您仍然必须编写脚本来加载测试数据,并在每次测试运行之间使用脚本来重置测试数据。许多测试将依赖于特定的数据集,并且随着您添加测试,这变得更难维护。当然,随着实际应用程序的发展,所有这些设置都需要与您的实际应用程序保持同步。根据应用程序,这可能会非常耗时。有些应用程序有数千个测试,当应用程序的一个简单更改导致 20 个测试及其数据集必须重写时,这令人心碎。

话虽如此,使用 DBUnit 有一个学习曲线,第一次使用它可能会有点耗时。一旦它为一项测试准备就绪,它就可以为后续测试节省时间。我没有在任何地方使用它,因为我编写了很多依赖于实际服务器的测试,但是我编写的新代码和测试尝试建立在我最初的 DBUnit 设置上,并且显然这确实节省了时间 从长远来看。

我的 2 美分,再见的朋友。

【讨论】:

  • 感谢您的帖子。我开始(再次!)思考如何使用真实的数据库来做到这一点,并开始意识到你提到的一些问题会出现。 但是这似乎是最简单的入门方法,而且我们可能必须在这个模拟数据库中输入大量测试数据以使其有用。那么,stef 你能给我一些关于如何使用 DBUnit 的指示吗?对我来说更重要的是,是否有可能在套件中的每个测试中增加一个模拟数据库?我该怎么做呢?
【解决方案4】:

以前对我有用的一种技术是直接模拟数据库适配器并将模拟注入依赖链。但是,这仅适用于非常 单元,因为让模拟适配器返回您希望从特定查询中返回的数组结构是一件很痛苦的事情。如果单个方法调用涉及多个查询,则根本不起作用。

我成功使用的另一种策略是使用 dbUnit 来设置和拆卸数据库。夹具数据存储在 XML 或 Yaml 文件中,并在每次测试前导入空数据库,提供已知状态。给定一个模式和一个最小数据集,内存数据库将通过避免磁盘 I/O 问题来合理地快速运行测试。

最后,考虑一下您是否甚至需要为数据持久性编写测试...如果您正在测试 ActiveRecord 实现,您可能有一些测试可以证明库级别的基本 CRUD 操作.您真正对测试感兴趣的内容并不依赖于数据库,而是在给定已知起点时内存中的对象会按预期运行。您可以通过在内存中创建对象来获得一个已知的起点,而无需从数据库中加载或保存到数据库中。

只需通过创建一些对象来设置内存中的预期状态、执行业务逻辑、询问最终状态,而不必费心调用“保存”......或者任何你称之为的东西。如果您所需要的只是一个看起来像数据库连接以满足依赖关系的对象,那么您就有了一个模拟对象......

【讨论】:

  • 感谢您的意见,大卫。我喜欢你关于根本不需要数据库的建议,我想这是编写代码的理想情况,这样它就可以在不需要数据库的情况下进行单元测试。不幸的是,我们的代码没有考虑到这一点,所以根本不需要数据库可能还很遥远。更糟糕的是,当其他更紧急的事情出现时,我不得不把单元测试的东西放在次要位置。伙计,这总是发生! :(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-22
  • 2011-10-24
  • 1970-01-01
  • 2022-12-07
  • 1970-01-01
相关资源
最近更新 更多