Pregunta

Estoy utilizando PHPUnit, pero les resulta difícil hacer que crear buenas burla y talones para los objetos que se utilizan como almacén de datos.

Ejemplo:

class urlDisplayer {
    private $storage;
    public function __construct(IUrlStorage $storage) { $this->storage = $storage; }
    public function displayUrl($name) {}
    public function displayLatestUrls($count) {}
}

interface IUrlStorage {
    public function addUrl($name, $url);
    public function getUrl($name);
}

class MysqlUrlStorage implements IUrlStorage {
    // saves and retrieves from database
}

class NonPersistentStorage implements IUrlStorage {
    // just stores for this request
}

Por ejemplo, cómo tener talones de PHPUnit regresan más de un valor posible en dos llamadas con nombres diferentes $?

Edit: ejemplo de prueba:

public function testUrlDisplayerDisplaysLatestUrls {
    // get mock storage and have it return latest x urls so I can test whether
    // UrlDisplayer really shows the latest x
}

En esta prueba el simulacro debe devolver un número de direcciones URL, sin embargo en la documentación sólo la forma de devolver un valor.

¿Fue útil?

Solución

Su pregunta no es muy clara - pero supongo que usted está pidiendo cómo utilizar los objetos de imitación de PHPUnit para devolver un valor diferente en diferentes situaciones

?

clases simulacros de PHPUnit le permiten especificar una función personalizada. (Es decir: una función de devolución de llamada / método) - que es prácticamente ilimitada en lo que puede hacer

En el siguiente ejemplo, he creado una clase IUrlStorage maqueta que devolverá la siguiente url en su almacenamiento cada vez que se llama.

public function setUp()
{
    parent::setUp();
    $this->fixture = new UrlDisplayer(); //change this to however you create your object

    //Create a list of expected URLs for testing across all test cases
    $this->expectedUrls = array(
          'key1' => 'http://www.example.com/url1/'
        , 'key2' => 'http://www.example.net/url2/'
        , 'key3' => 'http://www.example.com/url3/'
    );
}

public function testUrlDisplayerDisplaysLatestUrls {
    //Init        
    $mockStorage = $this->getMock('IUrlStorage');
    $mockStorage->expects($this->any())
        ->method('getUrl')
        ->will( $this->returnCallback(array($this, 'mockgetUrl')) );

    reset($this->expectedUrls); //reset array before testing

    //Actual Tests
    $this->assertGreaterThan(0, count($this->expectedUrls));
    foreach ( $this->expectedUrls as $key => $expected ) {
        $actual = $this->fixture->displayUrl($key);
        $this->assertEquals($expected, $actual);
    }
}

public function mockGetUrl($name)
{
    $value = current($this->expectedUrls);
    next($this->expectedUrls);

    //Return null instead of false when end of array is reached
    return ($value === false) ? null : $value;
}

Por otra parte, a veces es más fácil simplemente crear una clase real que se burla de la funcionalidad necesaria. Esto es especialmente fácil con interfaces bien definidas y pequeñas.

En este caso específico, se recomienda usar la clase de abajo en su lugar:

class MockStorage implements IUrlStorage
{
    protected $urls = array();

    public function addUrl($name, $url)
    {
        $this->urls[$name] = $url;
    }

    public function getUrl($name)
    {
        if ( isset($this->urls[$name]) ) {
            return $this->urls[$name];
        }
        return null;
    }
}
?>

A continuación, en la clase de prueba de la unidad simplemente instancie su accesorio, como a continuación:

public function setUp() {
   $mockStorage = new MockStorage();

   //Add as many expected URLs you want to test for
   $mockStorage->addUrl('name1', 'http://example.com');
   //etc...

   $this->fixture = new UrlDisplayer($mockStorage);
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top