2010-06-29 13 views
33

Tengo dificultades para burlarme del objeto PDO con PHPUnit.Burlarse del objeto PDO utilizando PHPUnit

No parece ser mucho más información en la web acerca de mi problema, pero de lo que he entendido:

  1. DOP tiene __wakeup 'final' y métodos __sleep que le impiden ser serializado.
  2. La implementación de objetos ficticios de PHPunit serializa el objeto en algún momento.
  3. Las pruebas de la unidad luego fallan con un error PHP generado por PDO cuando esto ocurre.

Hay una característica destinadas a evitar este comportamiento, añadiendo la siguiente línea a su unidad de prueba:

class MyTest extends PHPUnit_Framework_TestCase 

{  
    protected $backupGlobals = FALSE; 
    // ... 

} 

Fuente: http://sebastian-bergmann.de/archives/797-Global-Variables-and-PHPUnit.html

Esto no es trabajo para mí, mi prueba sigue produciendo un error.

completo código de prueba:

class MyTest extends PHPUnit_Framework_TestCase 
{ 

    /** 
    * @var MyTest 
    */ 
    private $MyTestr; 

    protected $backupGlobals = FALSE; 

    /** 
    * Prepares the environment before running a test. 
    */ 
    protected function setUp() 
    { 
     parent::setUp(); 

    } 

    /** 
    * Cleans up the environment after running a test. 
    */ 
    protected function tearDown() 
    { 

     parent::tearDown(); 
    } 

    public function __construct() 
    { 

     $this->backupGlobals = false; 
     parent::__construct(); 

    } 


    /** 
    * Tests MyTest->__construct() 
    */ 
    public function test__construct() 
    { 

     $pdoMock = $this->getMock('PDO', array('prepare'), array(), '', false); 

     $classToTest = new MyTest($pdoMock); 

     // Assert stuff here! 


    } 

    // More test code....... 

Cualquier PHPUnit pro de darme una mano?

Gracias,

Ben

Respuesta

47

backupGlobals $ no le ayuda, porque este error viene de otra parte. PHPUnit 3.5.2 (posiblemente versiones anteriores también) tiene el siguiente código en PHPUnit/Marco/MockObject/Generator.php

if ($callOriginalConstructor && 
     !interface_exists($originalClassName, $callAutoload)) { 
     if (count($arguments) == 0) { 
      $mockObject = new $mock['mockClassName']; 
     } else { 
      $mockClass = new ReflectionClass($mock['mockClassName']); 
      $mockObject = $mockClass->newInstanceArgs($arguments); 
     } 
    } else { 
     // Use a trick to create a new object of a class 
     // without invoking its constructor. 
     $mockObject = unserialize(
      sprintf(
      'O:%d:"%s":0:{}', 
      strlen($mock['mockClassName']), $mock['mockClassName'] 
     ) 
     ); 
    } 

Este "truco" con unserialize se utiliza cuando se pide getMock a no ejecutar el constructor original, y fracasará rápidamente con PDO.

Entonces, ¿cómo funciona alrededor?

Una opción es crear un ayudante prueba como esta

class mockPDO extends PDO 
{ 
    public function __construct() 
    {} 

} 

El objetivo aquí es la de deshacerse del constructor original de DOP, lo que no es necesario. A continuación, cambie el código de prueba para esto:

$pdoMock = $this->getMock('mockPDO', array('prepare')); 

Creación de maqueta como esto se ejecutar el constructor original, pero puesto que ahora es inofensivos gracias a ayudante de prueba mockPDO, se puede continuar con las pruebas.

+0

Esto hace el trabajo. ¡Gracias! – uckelman

+1

¡Eres el papá! Muchas gracias, esto funciona bien. ¡Había renunciado a resolver este problema! –

+0

Tuve el mismo problema que el póster original y utilicé su solución. Sin embargo, ahora mi tipificación ya no lo veo como PDO. 'debe ser una instancia de PDO, instancia de Mock_PDOMock_96936f72 dado' – nvanesch

2

Lo mejor que se me ocurre es utilizar runkit y redefinir los dos métodos finales como protegidos mediante runkit_function_redefine.

Dont para obtener habilitar la configuración runkit.internal_override en php.ini.

Y como siempre, al igual que con eval, si runkit parece que la respuesta, la pregunta es probablemente equivocado :)

+0

No creo que haya nada de malo con 'runkit' o' eval' con fines de prueba. – netcoder

1

¿Estás instanciando tu caso de prueba en tu caso de prueba?

$classToTest = new MyTest($pdoMock); 

En este momento, básicamente estás probando tu caso de prueba. Debería ser algo así como:

$classToTest = new My($pdoMock); 
+0

Eso definitivamente es un error en la pregunta original. – uckelman

Cuestiones relacionadas