【发布时间】:2013-01-07 16:28:06
【问题描述】:
我正在实现一个模块,该模块将提供一个 API 来处理和管理 PHP 会话。我正在测试Session\Manager 实现,它允许用户启动会话、设置ID、获取ID、销毁会话等。我正在使用PHPUnit 的@runInSeparateProcess 注释在单独的进程中测试此类中的方法。当我使用这个注释时,由于反序列化错误,我得到了 PHPUnit 抛出的异常。当我不使用注释时,测试按预期运行,并且在 null 不等于 false 时失败。
这是导致错误的测试。目前还没有实现细节,接口的所有方法都存在但不执行任何操作。
class ManagerTest extends PHPUnitTestCase {
/**
* Ensures that if the session has not been started yet the sessionExists
* method returns false.
*
* @runInSeparateProcess
*/
public function testSessionExistsWhenSessionHasNotBeenStarted() {
$Manager = new \Session\Manager();
$this->assertFalse($Manager->sessionExists());
}
}
我能够将问题追溯到以下PHPUnit_Util_PHP::runJob() 方法。我正在运行 PHPUnit 3.7.5,被调用的 runJob 方法是:
/**
* Runs a single job (PHP code) using a separate PHP process.
*
* @param string $job
* @param PHPUnit_Framework_TestCase $test
* @param PHPUnit_Framework_TestResult $result
* @return array|null
* @throws PHPUnit_Framework_Exception
*/
public function runJob($job, PHPUnit_Framework_Test $test = NULL, PHPUnit_Framework_TestResult $result = NULL)
{
$process = proc_open(
$this->getPhpBinary(),
array(
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
2 => array('pipe', 'w')
),
$pipes
);
if (!is_resource($process)) {
throw new PHPUnit_Framework_Exception(
'Unable to create process for process isolation.'
);
}
if ($result !== NULL) {
$result->startTest($test);
}
$this->process($pipes[0], $job);
fclose($pipes[0]);
$stdout = stream_get_contents($pipes[1]);
fclose($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
proc_close($process);
$this->cleanup();
if ($result !== NULL) {
$this->processChildResult($test, $result, $stdout, $stderr);
} else {
return array('stdout' => $stdout, 'stderr' => $stderr);
}
}
$stdout = stream_get_contents($pipes[1]); 行导致$stdout 等于? 的长字符串。在$this->processChildResult 中,$stdout 中的值未序列化,传递给此函数的无效值会触发警告,从而引发异常。我还能够确定$this->getPhpBinary() 的返回值是/usr/bin/php。
抛出异常消息:
PHPUnit_Framework_Exception: ???...???"*???...??
Caused by
ErrorException: unserialize(): Error at offset 0 of 10081 bytes
感谢 hek2mgl,$job 中的 PHP 代码可以在 at this gist holding the output of a var_dump on $job 中查看。我创建了一个链接,因为它是相当多的代码,而且这个问题已经很长了。
我对这个特定领域的知识已经到了尽头,不知道如何进一步调试这个问题。我不确定为什么 @runInSeparateProcess 失败以及为什么 $stdout 运行单独的进程会导致一长串 ?分数。什么可能导致此问题,我该如何解决?我对这个模块处于停顿状态,因为未来的测试需要在单独的进程中运行,以确保会话的启动和销毁不会影响测试。
- PHP:5.3.15
- PHPUnit:3.7.5
- 在 IDE 和命令行测试运行程序中导致错误
【问题讨论】:
-
嘿!有趣的问题。不久前我遇到了
runJob()的一些问题。也许你可以从 github 克隆我的 hexdump 包,看看里面到底是什么???...???字符串。 -
另外(也许更容易)你可以做
die($job);或其他任何事情来获得这份工作.. 这份工作是一个 php 文件,正如你提到的那样,将使用/usr/bin/php执行。该脚本返回序列化的 php 数据作为输出。真的很想看到那个输出!!! :) 请在抓取代码后手动执行并将其添加到问题中 -
@hek2mgl 获取
$job变量的输出的好主意。我现在正在审查它,以确保没有任何可能保密的信息被泄露。我将使用输出链接更新答案。 -
如果没有其他必需的文件,我无法执行测试,因此不能说太多。当你像我在回答中提到的那样执行它时,脚本会输出什么?
-
@hek2mgl 我能够将问题的一部分追溯到 $GLOBAL['__PHPUNIT_BOOTSTRAP'] 要求失败并导致致命错误。但是,即使我注释掉或临时修复到已知路径并尝试反序列化输出,对于指示错误的返回值,我也会得到 false。还有一些其他的事情正在发生,我需要尝试追踪。但恐怕这一切都得等到明天了。