2011-03-17 15 views
8

Estoy tratando de probar una clase de mapeador con PHPUnit. Me puedo burlar fácilmente de la instancia de PDO que se inyectará en la clase de correlacionador, pero no puedo imaginarme cómo simular la clase PreparedStatement, ya que está generada por la clase PDO.PHPUnit - Cómo simular la declaración preparada de PDO

En mi caso he extendido la clase DOP, así que tengo esto:

public function __construct($dsn, $user, $pass, $driverOptions) 
{ 

    //... 

    parent::__construct($dsn, $user, $pass, $driverOptions); 
    $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, 
     array('Core_Db_Driver_PDOStatement', array($this))); 
} 

El punto es que Core_Db_Driver_PDOStatement no se inyecta en el constructor de la clase PDO, es instanciado estáticamente. E incluso si hago esto:

public function __construct($dsn, $user, $pass, $driverOptions, $stmtClass = 'Core_Db_Driver_PDOStatement') 
{ 

    //... 

    parent::__construct($dsn, $user, $pass, $driverOptions); 
    $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, 
     array($stmtClass, array($this))); 
} 

... sigue siendo un instanciation estática ya que no puedo pasar mi propia instancia de la clase imitó declaración preparada.

¿Alguna idea?

Editar: solución, adaptada de la anwser:

/** 
* @codeCoverageIgnore 
*/ 
private function getDbStub($result) 
{ 
    $STMTstub = $this->getMock('PDOStatement'); 
    $STMTstub->expects($this->any()) 
      ->method('fetchAll') 
      ->will($this->returnValue($result)); 


    $PDOstub = $this->getMock('mockPDO'); 
    $PDOstub->expects($this->any()) 
      ->method('prepare') 
      ->will($this->returnValue($STMTstub)); 

    return $PDOstub; 
} 

public function testGetFooById() 
{ 
    $arrResult = array(...); 
    $PDOstub = $this->getDbStub($arrResult); 
} 

Respuesta

10

Si puede burlarse de la clase DOP simplemente se burlan de la clase PDO y todas sus dependencias. No debería ser necesario preocuparse por la clase de sentencia o el constructor de la clase pdo, ya que define la entrada y la salida a través de los simulacros.

Así que necesita un objeto simulado que devuelva un objeto simulado.

Puede parecer un poco confuso, pero dado que solo debe probar lo que hace la clase bajo prueba y nada más, puede prácticamente deshacerse de todas las otras partes de su conexión de base de datos.

En este ejemplo todo lo que quiere averiguar es:

  • es preparar llamada?
  • ¿Se llama a fetch para que prepare devoluciones?
  • ¿Se devuelve el resultado de esa llamada?

Si es así: Todo bien.

<?php 
class myClass { 
    public function __construct(ThePDOObject $pdo) { 
     $this->db = $pdo; 
    } 

    public function doStuff() { 
     $x = $this->db->prepare("..."); 
     return $x->fetchAll(); 
    } 
} 

class myClassTest extends PHPUnit_Framework_TestCase { 

    public function testDoStuff() { 

     $fetchAllMock = $this 
      ->getMockBuilder("stdClass" /* or whatever has a fetchAll */) 
      ->setMethods(array("fetchAll")) 
      ->getMock(); 
     $fetchAllMock 
      ->expects($this->once())->method("fetchAll") 
      ->will($this->returnValue("hello!")); 

     $mock = $this 
      ->getMockBuilder("ThePDOObject") 
      ->disableOriginalConstructor() 
      ->setMethods(array("prepare")) 
      ->getMock(); 
     $mock 
      ->expects($this->once()) 
      ->method("prepare") 
      ->with("...") 
      ->will($this->returnValue($fetchAllMock)); 

     $x = new myClass($mock); 
     $this->assertSame("hello!", $x->doStuff()); 


    } 

} 
+0

Exactamente, que se encontró la parte que no entendía demasiado bien: no hay necesidad de inyectar la Declaración cuando se puede falso que fetchAll volverá algo que se puede decidir en la prueba. He editado mi pregunta para colocar mi solución adaptada. Gracias ! – FMaz008

+1

El problema con este enfoque es que expone la implementación del código de la aplicación a la prueba. ¿Debería la prueba saber si la aplicación llama a -> fetch() o fetchAll()? ¡De ningún modo! Si el código está adaptado para usar fetch() en lugar de fetchaAll(), el método aún puede funcionar correctamente pero la prueba fallará. –

+1

@TomB, este es un problema general con las dependencias de burla, no solo con esta respuesta. – PeerBr

Cuestiones relacionadas