php – 尝试使用VFSStream测试文件系统操作
我正在尝试使用vfsStream来模拟文件系统操作(实际上是从php://输入读取),但缺乏体面的文档和示例实际上是在妨碍我.
我正在测试的类的相关代码如下: class RequestBody implements ifacerequestRequestBody { const REQ_PATH = 'php://input',protected $requestHandle = false; /** * Obtain a handle to the request body * * @return resource a file pointer resource on success,or <b>FALSE</b> on error. */ protected function getHandle () { if (empty ($this -> requestHandle)) { $this -> requestHandle = fopen (static::REQ_PATH,'rb'); } return $this -> requestHandle; } } 我在PHPUnit测试中使用的设置如下: protected function configureMock () { $mock = $this -> getMockBuilder ('gordianreefknothttprequestRequestBody'); $mock -> setConstructorArgs (array ($this -> getMock ('gordianreefknothttpifaceRequest'))) -> setMethods (array ('getHandle')); return $mock; } /** * Sets up the fixture,for example,opens a network connection. * This method is called before a test is executed. */ protected function setUp () { vfsStreamWrapper::register(); vfsStream::setup ('testReqBody'); $mock = $this -> configureMock (); $this -> object = $mock -> getMock (); $this -> object -> expects ($this -> any ()) -> method ('getHandle') -> will ($this -> returnCallback (function () { return fopen ('vfs://testReqBody/data','rb'); })); } 在实际测试中(调用间接触发getHandle()的方法)我尝试设置VFS并运行断言,如下所示: public function testBodyParsedParsedTrue () { // Set up virtual data $fh = fopen ('vfs://testReqBody/data','w'); fwrite ($fh,'test write 42'); fclose ($fh); // Make assertion $this -> object -> methodThatTriggersGetHandle (); $this -> assertTrue ($this -> object -> methodToBeTested ()); } 这只会导致测试挂起. 显然我在这里做了一些非常错误的事情,但考虑到文档的状态,我无法弄清楚它是什么意思.这是由vfsstream引起的,还是phpunit嘲笑我需要在这里查看的东西?
那么……如何测试流?所有vfsStream都提供了用于文件系统操作的自定义流包装器.您不需要完整的vfsStream库来模拟单个流参数的行为 – 它不是正确的解决方案.相反,您需要编写和注册自己的一次性流包装器,因为您不是要模拟文件系统操作.
假设你有以下简单的类来测试: class ClassThatNeedsStream { private $bodyStream; public function __construct($bodyStream) { $this->bodyStream = $bodyStream; } public function doSomethingWithStream() { return stream_get_contents($this->bodyStream); } } 在现实生活中你做: $phpInput = fopen('php://input','r'); new ClassThatNeedsStream($phpInput); 因此,为了测试它,我们创建了自己的流包装器,它将允许我们控制我们传入的流的行为.我不能详细介绍,因为自定义流包装器是一个很大的主题.但基本上这个过程是这样的: >创建自定义流包装器 所以你的自定义流看起来像: class TestingStreamStub { public $context; public static $position = 0; public static $body = ''; public function stream_open($path,$mode,$options,&$opened_path) { return true; } public function stream_read($bytes) { $chunk = substr(static::$body,static::$position,$bytes); static::$position += strlen($chunk); return $chunk; } public function stream_write($data) { return strlen($data); } public function stream_eof() { return static::$position >= strlen(static::$body); } public function stream_tell() { return static::$position; } public function stream_close() { return null; } } 然后在你的测试用例中你会这样做: public function testSomething() { stream_wrapper_register('streamTest','TestingStreamStub'); TestingStreamStub::$body = 'my custom stream contents'; $stubStream = fopen('streamTest://whatever','r+'); $myClass = new ClassThatNeedsStream($stubStream); $this->assertEquals( 'my custom stream contents',$myClass->doSomethingWithStream() ); stream_wrapper_unregister('streamTest'); } 然后,您可以简单地更改我在流包装器中定义的静态属性,以更改从读取流中返回的数据.或者,扩展基本流包装器类并注册它,以便为测试提供不同的方案. 这是一个非常基本的介绍,但重点在于:除非你嘲笑实际的文件系统操作,否则不要使用vfsStream – 这就是它的设计目的.否则,编写自定义流包装器以进行测试. PHP提供了一个原型流包装类来帮助您入门:http://www.php.net/manual/en/class.streamwrapper.php (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |