0

我正在用 PHPUnit 编写一些测试,最近,我遇到了标志选项:--process-isolation在阅读了它在单独的 PHP 进程中运行每个测试之后,我认为在执行我的测试套件。但是,它不断引发异常,例如:

PHPUnit_Framework_Exception: stty: Standard Input: Invalid Argument

或者有时:

PHPUnit_Framework_Exception: Notice: Constant PEAR_ERROR_RETURN already defined in /usr/share/php/PEAR.php on line 25
Notice: Constant PEAR_ERROR_PRINT already defined in /usr/share/php/PEAR.php on line 26
Notice: Constant PEAR_ERROR_TRIGGER already defined in /usr/share/php/PEAR.php on line 27
Notice: Constant PEAR_ERROR_DIE already defined in /usr/share/php/PEAR.php on line 28
Notice: Constant PEAR_ERROR_CALLBACK already defined in /usr/share/php/PEAR.php on line 29
Notice: Constant PEAR_ERROR_EXCEPTION already defined in /usr/share/php/PEAR.php on line 34
Notice: Constant PEAR_ZE2 already defined in /usr/share/php/PEAR.php on line 37
Notice: Constant OS_WINDOWS already defined in /usr/share/php/PEAR.php on line 44
Notice: Constant OS_UNIX already defined in /usr/share/php/PEAR.php on line 45
Notice: Constant PEAR_OS already defined in /usr/share/php/PEAR.php on line 46

第一个异常仅在我激活进程隔离标志时出现,而我没有它,测试运行顺利且没有任何问题。第二个异常,起初,我认为这可能是由于包含冲突,但在查看并将所有包含更改为 include_once 之后,异常仍然不断出现。

任何帮助将不胜感激。

4

2 回答 2

1

我已经深入研究了这个问题。我将根据假设使用 PHPUnit 3.7 来解释发生了什么。

当您使用进程隔离时,PHPUnit 仍然会将全局状态注入子进程。在这一点上,我可能会听到一些反对者说默认情况下启用 preserveGlobalState 与 runInSeparateProcess 的意图相矛盾。在我意识到 phpunit.xml 具有定义全局变量/常量/includePath 的部分之前,我采用相同的方式 - 如果没有 preserveGlobalState,这些设置将永远不会进入子进程。所以现在我确信在大多数情况下都需要向子进程注入全局状态:我们需要做的就是确保这个全局状态足够干净,可以运行测试。

Sebastian Bergmann 已经编写了一些代码来导出全局/常量/必需文件并将其放入 Smarty 模板中,该模板反过来成为 chlid 进程的 PHP 脚本。然而,他犯了一个小错误(在我看来):他在所需文件之前加载常量,而不是之后。这有很大的不同!这里的例子:

所需文件.php:

<?php

define("SOME_CONSTANT", true);

class RequiredClass
 {
 }

?>

当这个文件被父 PHPUnit 进程加载时,它定义了常量并将 requiredfile.php 添加到包含文件的列表中。

然后 PHPUnit 为孩子制作 PHP 脚本,基本上看起来像:

<?php

define("SOME_CONSTANT", true);

require_once "requiredfile.php";

?>

当然,它会导致 PHP 触发由 PHPUnit 转换为异常的错误(已定义常量),因为它不知道此错误不是由测试代码触发的,而是由 PHPUnit 生成的代码触发的。

但是,此代码中的常量定义具有 if (defined()) ,因此如果我们仅将常量定义放在所需文件之后,则不会发生常量重新定义,因此不会出现错误。

PHPT 测试失败的罪魁祸首是 PEAR.php,您无法避免它,因为 PHPUnit 使用 PEAR 的 RunTest。因此,除非您在 PHPUnit 3.7 中修复 Smarty 模板,否则您将无法运行任何 PHPT 测试以及任何使用进程隔离的测试。

那么你需要做什么?简单的!前往 PHPUnit/Framework/Process/TestCaseMethod.tpl.dist 并交换 {constants} 和 {included_files} 。这可能不是每个人的最佳解决方案 - 特别是如果您无法更改 PHPUnit 文件。但我个人认为它是 PHPUnit 中的一个错误,因此有必要进行此类修复。

于 2014-10-20T17:58:39.563 回答
0

尝试添加:

/**
 * @runInSeparateProcess
 * @preserveGlobalState disabled
 */

到您的测试上方的 PHPDoc,而不是使用命令行选项。该标志可能仍在测试之间保留全局变量。

于 2013-07-27T05:48:37.990 回答