Php @runinsepareprocess时出现取消序列化错误
我正在实现一个模块,该模块将提供一个用于处理和管理PHP会话的API。我正在测试允许用户启动会话、设置ID、获取ID、销毁会话等的Php @runinsepareprocess时出现取消序列化错误,php,phpunit,Php,Phpunit,我正在实现一个模块,该模块将提供一个用于处理和管理PHP会话的API。我正在测试允许用户启动会话、设置ID、获取ID、销毁会话等的Session\Manager实现。我正在使用PHPUnit的@runinsepareprocess注释,在单独的过程中测试此类中的方法。使用此注释时,由于非序列化错误,PHPUnit引发异常。当我不使用注释时,测试按预期运行,并在null不等于false时失败 这是导致错误的测试。到目前为止还没有实现细节,接口的所有方法都存在,但不执行任何操作 class Mana
Session\Manager
实现。我正在使用PHPUnit的@runinsepareprocess
注释,在单独的过程中测试此类中的方法。使用此注释时,由于非序列化错误,PHPUnit引发异常。当我不使用注释时,测试按预期运行,并在null不等于false时失败
这是导致错误的测试。到目前为止还没有实现细节,接口的所有方法都存在,但不执行任何操作
class ManagerTest扩展了phpunitestcase{
/**
*确保如果会话尚未启动,则会话存在
*方法返回false。
*
*@runinsepareprocess
*/
公共函数testsessionexistswhensessionhasnotbenstarted(){
$Manager=new\Session\Manager();
$this->assertFalse($Manager->sessionExists());
}
}
我能把问题归结到以下方法。我正在运行PHPUnit 3.7.5,调用的runJob
方法是:
/**
*使用单独的PHP进程运行单个作业(PHP代码)。
*
*@param string$job
*@param PHPUnit_Framework_TestCase$test
*@param PHPUnit_Framework_TestResult$result
*@return数组| null
*@throws PHPUnit_Framework_异常
*/
公共函数runJob($job,PHPUnit\u Framework\u Test$Test=NULL,PHPUnit\u Framework\u TestResult$result=NULL)
{
$process=proc\U open(
$this->getPhpBinary(),
排列(
0=>数组('pipe','r'),
1=>数组('pipe','w'),
2=>数组('pipe','w')
),
$pipes
);
如果(!is_资源($process)){
抛出新的PHPUnit\u框架\u异常(
“无法为进程隔离创建进程。”
);
}
如果($result!==NULL){
$result->startTest($test);
}
$this->process($pipes[0],$job);
fclose($pipes[0]);
$stdout=stream\u get\u内容($pipes[1]);
fclose($pipes[1]);
$stderr=流内容($pipes[2]);
fclose($pipes[2]);
过程结束($过程);
$this->cleanup();
如果($result!==NULL){
$this->processChildResult($test,$result,$stdout,$stderr);
}否则{
返回数组('stdout'=>$stdout,'stderr'=>$stderr);
}
}
行$stdout=stream\u get\u 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代码可以查看。我创建了一个链接,因为这是一个相当多的代码,这个问题已经相当长了
我对这个特定领域的知识已经到了极限,不知道如何进一步调试这个问题。我不知道为什么@runinsepareprocess
会失败,为什么运行单独进程的$stdout
会导致一长串错误?标志。什么可能导致此问题?我如何着手解决此问题?由于未来的测试需要在一个单独的进程中运行,以确保启动和销毁的会话不会影响测试,因此我对该模块处于停顿状态
- PHP:5.3.15
- PHPUnit:3.7.5
- IDE和命令行测试运行程序中导致的错误
PHPUnit\u Util\u PHP::runJob()的$job参数是PHPUnit生成的PHP代码,它以一种可以作为命令行脚本执行的方式包装测试方法的代码(巧妙的技巧!)。
独立测试将把有关测试结果的序列化php数据输出回phpunit
如果要在pfPHPUnit\u Util\u PHP::runJob()的顶部添加以下行,则可以研究此代码
再次执行失败的测试后,应在当前目录中创建文件isolated.php
。您可以查看代码,您可以通过键入来执行它(在当前文件夹中)
php isolated.php
您是否看到任何看起来很混乱的输出
您还应该调试方法PHPUnit\u Util\u PHP::processChildResult()
。该方法负责反序列化和检查测试结果。在那里放置一些echo或var_转储或使用调试器。当查看此方法时,问题很可能是由测试方法的非法输出引起的。好的,我知道这里发生了什么,男孩,这是一个傻瓜
在测试期间,框架试图保持全局状态。在PHPUnit\u Framework\u TestCase::run()
函数中,当前全局变量通过PHPUnit\u Util\u GlobalState::getGlobalsAsString()
转换为PHP代码字符串。我目前正在使用自动加载库来处理需要适当的类文件的问题。该类在全局作用域中的变量中声明,导致将该对象的序列化放入由getGlobalAssString()
创建的$GLOBALS
数组中。无论出于何种原因,此序列化都包括空字节字符\u0000
。当您尝试取消序列化时,会出现错误,并最终导致输出损坏
我通过在测试引导中创建一个函数修复了这个问题,该函数在全局范围之外创建自动加载对象。既然脚本不再尝试取消序列化空字节,那么脚本就不会产生错误,测试用例也会按预期工作。这
php isolated.php
class ManagerTest extends PHPUnit_Framework_TestCase {
public function run(PHPUnit_Framework_TestResult $result = null) {
$this->setPreserveGlobalState(false);
parent::run($result);
}
}