那么...如何使用流进行测试? 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);
因此,为了测试它,我们创建了自己的流包装器,它将允许我们控制传入的流的行为。我无法详细介绍,因为自定义流包装器是一个很大的主题。But基本上这个过程是这样的:
- 创建自定义流包装器
- 使用 PHP 注册该流包装器
- 使用注册的流包装器方案打开资源流
所以你的自定义流看起来像:
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 http://www.php.net/manual/en/class.streamwrapper.php