2012-07-28 11 views
8

Próbuję sfałszować działanie systemu plików (właściwie odczyt z php: // input) za pomocą vfsStream, ale brak porządnej dokumentacji i przykładów naprawdę przeszkadza mi.Próbuję przetestować działanie systemu plików za pomocą VFSStream

Odpowiedni kod z klasy jestem badania jest następujący:

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

Konfiguracja używam w moim teście PHPUnit jest następujący:

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

W teście (który wywołuje metodę, która pośrednio wywołuje getHandle()) staram się skonfigurować i uruchomić VFS twierdzenie następująco:

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

Powoduje to zawieszenie testu.

Oczywiście robię tutaj coś bardzo złego, ale biorąc pod uwagę stan dokumentacji, nie jestem w stanie ustalić, co to jest, co mam robić. Czy jest to coś spowodowane przez vfsstream, czy też phpunit kpi z rzeczy, których muszę tu szukać?

+0

VFSStream jest niepotrzebny kompleks kawałek zestawie ze wszystkimi podklasy i nazw itp wszystko musi być podejście klasowe. To jest opakowanie dla opakowania. Napisałem tylko jedną klasę opartą na interfejsie phip StreamWrapper i to wystarcza, aby wykonać zadanie. Zobacz także: http://php.net/manual/en/class.streamwrapper.php – Codebeat

Odpowiedz

9

Więc ... jak przetestować za pomocą strumieni? Wszystko, co robi vfsStream, zapewnia niestandardowe opakowanie strumieniowe dla operacji systemu plików. Nie potrzebujesz pełnej biblioteki vfsStream tylko po to, aby kpić z zachowania pojedynczego strumienia - nie jest to poprawne rozwiązanie. Zamiast tego musisz napisać i zarejestrować własne opakowanie jednorazowe, ponieważ nie próbujesz kpić z operacji systemu plików.

Powiedzmy, że masz następującą prostą klasę do testu:

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

w prawdziwym życiu zrobić:

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

więc przetestować go, tworzymy nasz własny strumień owijkę, która pozwoli nam kontroluj zachowanie strumienia, przez który przechodzimy. Nie mogę przejść do zbyt wielu szczegółów, ponieważ niestandardowe obwoluty strumienia są dużym tematem. Ale zasadzie proces idzie tak:

  1. Tworzenie niestandardowych strumienia otoki
  2. Rejestrze, że opakowanie Strumienia z PHP
  3. Otwórz strumień zasób

Więc za pomocą zarejestrowanego programu otoki przesyłanie niestandardowy strumień wygląda tak:

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

Następnie w przypadku testowym byłoby to zrobić:

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

Następnie można po prostu zmienić właściwości statycznych Mam zdefiniowane w opakowaniu strumienia danych, aby zmienić to, co wraca z czytania strumienia. Możesz też rozszerzyć klasę pakowania strumienia podstawowego i zarejestrować ją, aby zapewnić różne scenariusze testów.

To jest bardzo podstawowe wprowadzenie, ale chodzi o to: nie używaj vfsStream, chyba że kpisz z rzeczywistych operacji na systemie plików - właśnie do tego został zaprojektowany. W przeciwnym razie napisz niestandardowe opakowanie strumieniowe do testowania.

PHP zapewnia strumień prototyp klasy otoki na początek: http://www.php.net/manual/en/class.streamwrapper.php

+1

Zgaduję, że będę musiał opuścić obmyślanie VFS na inny dzień. – GordonM

0

I zmagali się ze znalezieniem podobną odpowiedź - Znalazłem w dokumentacji brakuje również.

Podejrzewam Twój problem to, że vfs://testReqBody/data nie była droga do istniejącego pliku (jak php://input zawsze będzie).

Jeśli zaakceptowane odpowiedź jest dopuszczalna odpowiedź, to jest to równoznaczne z vfsStreamWrapper.

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

Alternatywnie, jeśli chcesz podzielić się to tak, że można zdefiniować zawartość po wywołaniu vfsStream::setup(), to w jaki sposób.

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

Inną rzeczą, aby pamiętać, ze swojego oryginalnego kodu, nie trzeba zadzwonić vfsStreamWrapper::register(); podczas korzystania vfsStream::setup()

Powiązane problemy