17

随着运行完整 PHPUnit 套件所需时间的增加,我们的团队开始怀疑是否有可能并行运行单元测试。最近我读到一篇关于 Paraunit 的文章,Sebastian Bergman 也写过,他将在 PHPUnit 3.7 中添加并行性。

但是集成测试,或者更一般地说,与数据库交互的测试仍然存在问题。为了保持一致性,必须在每次测试后重置 testDB 并加载固定装置。但是在并行测试中存在竞争条件的问题,因为所有进程都使用相同的 DB

因此,为了能够并行运行集成测试,我们必须为每个进程分配自己的数据库。我想问一下,如果有人对如何解决这个问题有一些想法。也许在另一个 xUnit 实现中已经实现了解决这个问题的方法。

在我的团队中,我们正在使用 MongoDB,因此一种解决方案是以编程方式为每个 PHPUnit 进程创建一个配置文件,并使用生成的数据库名称(为此进程),并且在setUp()方法中我们可以将主 TestDb 克隆到这个临时文件中。但在我们开始实施这种方法之前,我想询问您对该主题的想法。

4

4 回答 4

9

这是一个很好的问题:准备并行单元测试需要学习一些新的最佳实践,我怀疑其中一些会减慢我们的测试速度。

最高级别的建议是:尽可能避免使用数据库进行测试。抽象与数据库的所有交互,然后模拟该类。但是您已经注意到您的问题是关于集成测试的,这是不可能的。

在使用 PDO 时,我一般使用 sqlite::memory:每个测试都有自己的数据库。它是匿名的,并在测试结束时自动清理。(但是当您的实际应用程序不使用 sqlite 时,我注意到了一些问题:使用内存中的 sqlite DB 加速单元测试时避免 DB 依赖的建议

使用没有内存选项的数据库时,请使用随机名称创建数据库。如果并行化在 PHPUnit 进程级别,非常粗糙,您可以使用进程 pid。但这与随机名称相比并没有真正的优势。(我知道 PHP 是单线程的,但也许将来我们会有一个自定义的 phpUnit 模块,它使用线程并行运行测试;我们不妨为此做好准备。)

如果你有 xUnit 测试模式这本书,第 13 章是关于测试数据库的(相对较短)。第 8 章和第 9 章关于瞬态与持久性固定装置也很有用。而且,当然,本书的大部分内容都是关于抽象层,以使模拟更容易:-)

于 2013-06-11T00:22:13.593 回答
1

还有这个很棒的库(最快的)用于并行执行测试。它针对功能/集成测试进行了优化,提供了一种并行处理 N 个数据库的简单方法。

我们的旧代码库在 30 分钟内运行,现在使用 4 个处理器在 7 分钟内运行。

特征

  • 功能测试可以使用环境变量为每个处理器使用一个数据库。
  • 默认情况下,测试是随机的。
  • 不加上 PhpUnit 你可以运行任何命令。
  • 用 PHP 开发,没有依赖项。
  • 作为输入,您可以使用 phpunit.xml.dist 文件或使用管道。
  • 包括一个 Behat 扩展,可以轻松地将场景导入最快。
  • 使用 -v 选项增加详细程度。

用法

find tests/ -name "*Test.php" | ./bin/fastest "bin/phpunit -c app {};"

于 2017-01-31T16:29:40.870 回答
0

但是集成测试,或者更一般地说,与数据库交互的测试仍然存在问题。为了保持一致性,必须在每次测试后重置 testDB 并加载固定装置。但是在并行测试中存在竞争条件的问题,因为所有进程都使用相同的数据库。

因此,为了能够并行运行集成测试,我们必须为每个进程分配自己的数据库。我想问一下,如果有人对如何解决这个问题有一些想法。也许在另一个 xUnit 实现中已经实现了解决这个问题的方法。

您可以通过两种方式避免集成测试冲突:

  • 仅并行运行那些测试,它使用数据库的非常不同的表,因此它们不会冲突
  • 为冲突测试创建一个新数据库

办公室。您可以将这两种解决方案结合起来。我不知道有任何支持这些方法的 phpunit 测试运行器,所以我认为你必须编写自己的测试运行器来加快进程......顺便说一句,你仍然可以对集成测试进行分组,并且只运行几个如果您通过开发使用它们,请立即使用它们...

请注意,相同的冲突可能会在 PHP 的重负载下导致并发问题。例如,如果您在 2 个单独的控制器操作下以相反的顺序锁定 2 个文件,那么您的应用程序可能会陷入死锁......我正在寻找一种方法来测试 PHP 中的并发问题,但到目前为止还没有运气。我目前没有时间编写自己的解决方案,而且我不确定我是否可以管理它,这是非常困难的事情......:S

于 2014-04-07T15:50:49.613 回答
0

如果您的应用程序与特定供应商耦合,例如。postgresql 你可以使用 docker 和 docker-compose 创建单独的堆栈。然后按目的将测试组合在一起,例如。模型测试,控制器测试等。

对于每个组,使用 docker-compos 在您的管道中部署一个特定的堆栈,并通过 docker 运行测试。这个想法是拥有单独的环境和单独的数据库,因此您可以避免冲突。

于 2020-09-21T12:42:46.273 回答