gpt4 book ai didi

php - 尝试使用 VFSStream 测试文件系统操作

转载 作者:可可西里 更新时间:2023-11-01 12:33:45 26 4
gpt4 key购买 nike

我正在尝试使用 vfsStream 模拟文件系统操作(实际上是从 php://input 中读取),但缺乏合适的文档和示例确实阻碍了我。

我正在测试的类的相关代码如下:

class RequestBody implements iface\request\RequestBody
{
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 ('\gordian\reefknot\http\request\RequestBody');

$mock -> setConstructorArgs (array ($this -> getMock ('\gordian\reefknot\http\iface\Request')))
-> 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 mock 我需要在这里查看的东西?

最佳答案

那么...如何使用流进行测试? 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);

因此,为了对其进行测试,我们创建了自己的流包装器,使我们能够控制传入的流的行为。我无法详细介绍,因为自定义流包装器是一个很大的话题。 但是基本上这个过程是这样的:

  1. 创建自定义流包装器
  2. 用 PHP 注册流包装器
  3. 使用已注册的流包装器方案打开资源流

因此您的自定义流看起来像:

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 提供了一个原型(prototype)流包装器类来帮助您入门:http://www.php.net/manual/en/class.streamwrapper.php

关于php - 尝试使用 VFSStream 测试文件系统操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11700397/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com