2012-07-28 28 views
8

Tôi đang cố gắng thử nghiệm một hoạt động hệ thống tập tin (thực sự là đọc từ đầu vào php: //) với vfsStream nhưng thiếu tài liệu và ví dụ phong nha thực sự cản trở tôi.Đang cố gắng kiểm tra các hoạt động của hệ thống tập tin với VFSStream

Mã liên quan từ lớp tôi là thử nghiệm như sau:

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; 
    } 
} 

Quá trình cài đặt Tôi đang sử dụng trong thử nghiệm PHPUnit của tôi là như sau:

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'); 
        })); 
} 

Trong một thử nghiệm thực tế (mà gọi một phương pháp mà gián tiếp gây nên getHandle()) Tôi cố gắng thiết lập VFS và chạy một xác nhận như sau:

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()); 
} 

Điều này chỉ làm cho thử nghiệm bị treo.

Rõ ràng là tôi đang làm điều gì đó rất sai ở đây, nhưng với trạng thái của tài liệu, tôi không thể tìm ra điều tôi muốn làm. Đây có phải là một cái gì đó gây ra bởi vfsstream, hoặc là phpunit chế giễu điều tôi cần phải nhìn vào đây?

+0

VFSStream là mảnh phức tạp không cần thiết của bộ với tất cả các lớp con và không gian tên, vv tất cả mọi thứ phải là một cách tiếp cận lớp học. Nó là một wrapper cho một wrapper. Tôi đã viết chỉ một lớp dựa trên giao diện php StreamWrapper và đó là đủ để hoàn thành công việc. Xem thêm: http://php.net/manual/en/class.streamwrapper.php – Codebeat

Trả lời

9

Vậy ... làm cách nào để kiểm tra bằng luồng? Tất cả vfsStream đều cung cấp một trình bao bọc dòng tùy chỉnh cho các hoạt động của hệ thống tệp. Bạn không cần thư viện vfsStream đầy đủ chỉ để mô phỏng hành vi của một đối số luồng - đó không phải là giải pháp đúng. Thay vào đó, bạn cần viết và đăng ký trình bao bọc luồng một lần của riêng mình vì bạn không cố gắng thử nghiệm các hoạt động của hệ thống tệp.

Giả sử bạn có lớp đơn giản sau đây để kiểm tra:

class ClassThatNeedsStream { 
    private $bodyStream; 
    public function __construct($bodyStream) { 
     $this->bodyStream = $bodyStream; 
    } 
    public function doSomethingWithStream() { 
     return stream_get_contents($this->bodyStream); 
    } 
} 

Trong cuộc sống thực bạn làm:

$phpInput = fopen('php://input', 'r'); 
new ClassThatNeedsStream($phpInput); 

Vì vậy, để kiểm tra nó, chúng ta tạo ra dòng wrapper của riêng của chúng tôi mà sẽ cho phép chúng tôi kiểm soát hành vi của luồng mà chúng tôi truyền vào. Tôi không thể đi vào chi tiết quá nhiều vì trình bao bọc luồng tùy chỉnh là một chủ đề lớn. Nhưng về cơ bản quá trình này diễn ra như sau:

  1. Tạo luồng tùy chỉnh wrapper
  2. đăng ký mà dòng wrapper với PHP
  3. mở một dòng suối nguồn bằng cách sử dụng chương trình wrapper dòng đăng ký

Vì vậy bạn luồng tùy chỉnh trông giống như sau:

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; 
    } 
} 

Sau đó, trong trường hợp thử nghiệm của bạn, bạn sẽ làm điều này:

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'); 
} 

Sau đó, bạn chỉ có thể thay đổi các thuộc tính tĩnh tôi đã xác định trong wrapper dòng để thay đổi những gì dữ liệu trở lại từ việc đọc dòng. Hoặc, mở rộng lớp trình bao bọc cơ sở của bạn và đăng ký nó thay vào đó để cung cấp các kịch bản khác nhau cho các bài kiểm tra.

Đây là phần giới thiệu rất cơ bản, nhưng vấn đề là: không sử dụng vfsStream trừ khi bạn đang mô phỏng các hoạt động hệ thống tệp thực sự - đó là những gì nó được thiết kế cho. Nếu không, hãy viết trình bao bọc luồng tùy chỉnh để thử nghiệm.

PHP cung cấp một nguyên mẫu lớp dòng wrapper để giúp bạn bắt đầu: http://www.php.net/manual/en/class.streamwrapper.php

+1

Đoán tôi sẽ phải rời bỏ việc tìm ra VFS cho một ngày khác. – GordonM

0

tôi đã phải vật lộn với việc tìm kiếm một câu trả lời tương tự - Tôi tìm thấy tài liệu cũng thiếu.

tôi nghi ngờ vấn đề của bạn là vfs://testReqBody/data không phải là một đường dẫn đến một tập tin hiện có, (như php://input sẽ luôn luôn được.)

Nếu câu trả lời được chấp nhận là một câu trả lời có thể chấp nhận, thì đây là tương đương với vfsStreamWrapper.

<?php 
// ... 
$reqBody = "Request body contents" 
vfsStream::setup('testReqBody', null, ['data' => $reqBody]); 
$this->assertSame($reqBody, file_get_contents('vfs://testReqBody/data')); 

Ngoài ra, nếu bạn cần chia nhỏ này lên, chẳng hạn mà bạn xác định các nội dung sau khi gọi vfsStream::setup(), đây là như thế nào.

<?php 
//... 
$reqBody = "Request body contents" 
$vfsContainer = vfsStream::setup('testReqBody'); 
vfsStream::newFile('data')->at($vfsContainer)->setContent($reqBody); 
$this->assertSame($reqBody, file_get_contents('vfs://testReqBody/data')); 

Một điều khác cần lưu ý từ mã ban đầu của bạn, bạn không cần phải gọi vfsStreamWrapper::register(); khi sử dụng vfsStream::setup()

Các vấn đề liên quan