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

前端之家收集整理的这篇文章主要介绍了php – 尝试使用VFSStream测试文件系统操作前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在尝试使用vfsStream来模拟文件系统操作(实际上是从PHP://输入读取),但缺乏体面的文档和示例实际上是在妨碍我.

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

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嘲笑我需要在这里查看的东西?

那么……如何测试流?所有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);

因此,为了测试它,我们创建了自己的流包装器,它将允许我们控制我们传入的流的行为.我不能详细介绍,因为自定义流包装器是一个很大的主题.但基本上这个过程是这样的:

>创建自定义流包装器
>使用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

猜你在找的PHP相关文章