2010-06-29 4 views
33

Ho difficoltà a deridere l'oggetto PDO con PHPUnit.Mocking dell'oggetto PDO utilizzando PHPUnit

non sembra essere molto informazioni sul web circa il mio problema, ma da quello che ho potuto capire:

  1. DOP ha 'finale' __wakeup e metodi __sleep che impediscono che venga serializzato.
  2. L'implementazione di oggetti fittizi di PHP serializza l'oggetto a un certo punto.
  3. I test delle unità falliscono quindi con un errore PHP generato da PDO quando si verifica ciò.

C'è una funzione destinata a impedire questo comportamento, aggiungendo la seguente riga al test di unità:

class MyTest extends PHPUnit_Framework_TestCase 

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

} 

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

questo non è lavoro per me, la mia prova produce ancora un errore.

codice di prova completa:

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....... 

Qualsiasi PHPUnit pro me di dare una mano?

Grazie,

Ben

risposta

47

$ backupGlobals non ti aiuta, perché questo errore viene da altrove. PHPUnit 3.5.2 (versioni precedenti eventualmente pure) ha il seguente codice nel PHPUnit/quadro/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'] 
     ) 
     ); 
    } 

Questo "trucco" con unserialize viene utilizzato quando si chiede getMock di non eseguire il costruttore originale e prontamente fallirà con DOP.

Quindi, come aggirare?

Una possibilità è quella di creare un aiuto test come questo

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

} 

L'obiettivo qui è quello di sbarazzarsi del costruttore originale DOP, che non è necessario. Quindi, modificare il codice di prova per questo:

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

Creazione finto come questo sarà eseguire costruttore originale, ma dal momento che è ormai innocui grazie a mockPDO test di aiuto, è possibile continuare il test.

+0

Questo fa il lavoro. Grazie! – uckelman

+1

Sei il papà! Grazie mille, questo funziona bene Avevo rinunciato a risolvere questo problema! –

+0

Ho avuto lo stesso problema del poster originale e ho usato la soluzione. Comunque ora il mio typehinting non lo vede più come PDO. 'deve essere un'istanza di PDO, istanza di Mock_PDOMock_96936f72 data' – nvanesch

2

Il meglio che posso pensare è quello di utilizzare runkit e ridefinire i due metodi finali come protetti utilizzando runkit_function_redefine.

Non abilitare l'impostazione runkit.internal_override in php.ini.

E come sempre, come con eval, se runkit sembra la risposta, la domanda è probabilmente sbagliato :)

+0

Non credo che ci sia qualcosa di sbagliato con '' runkit' o eval' a scopo di test. – netcoder

1

Stai istanziando il tuo caso di test nel tuo caso di test?

$classToTest = new MyTest($pdoMock); 

In questo momento, si sta essenzialmente testando il proprio caso di test. Dovrebbe essere più qualcosa di simile:

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

Questo è sicuramente un bug nella domanda originale. – uckelman