2010-06-29 13 views
33

J'ai de la difficulté à me moquer de l'objet PDO avec PHPUnit.Mocking L'objet PDO utilisant PHPUnit

Il ne semble pas y avoir beaucoup d'informations sur le web au sujet de mon problème, mais de ce que je peux recueillir:

  1. AOP a __wakeup « finale » et méthodes de __sleep qui l'empêchent d'être sérialisé.
  2. L'implémentation de l'objet mock de PHPunit sérialise l'objet à un moment donné.
  3. Les tests unitaires échouent alors avec une erreur PHP générée par PDO lorsque cela se produit.

Il existe une fonction destinée à empêcher ce comportement, en ajoutant la ligne suivante à votre test unitaire:

class MyTest extends PHPUnit_Framework_TestCase 

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

} 

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

Ce isnt travail pour moi, mon test produit encore une erreur.

Code Test complet:

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

Toute PHPUnit pro me donner un coup de main?

Merci,

Ben

Répondre

47

$ backupGlobals ne vous aide pas, parce que cette erreur vient d'ailleurs. PHPUnit 3.5.2 (versions antérieures peut-être aussi) a le code suivant dans PHPUnit/Cadre/Mock Object/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'] 
     ) 
     ); 
    } 

Ce « truc » avec unserialize est utilisé lorsque vous demandez getMock de ne pas exécuter le constructeur d'origine et il échouera rapidement avec PDO.

Alors, comment le contourner?

Une option consiste à créer une aide de test comme celui-ci

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

} 

Le but ici est de se débarrasser du constructeur AOP d'origine, que vous n'avez pas besoin. Ensuite, modifiez votre code de test à ceci:

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

Création maquette comme ce sera exécuter constructeur d'origine, mais comme il est maintenant inoffensif grâce à helper test mockPDO, vous pouvez continuer à tester.

+0

Cela fait le travail. Merci! – uckelman

+1

Vous êtes le papa! Merci beaucoup cela fonctionne très bien. J'avais renoncé à résoudre ce problème! –

+0

J'ai eu le même problème que l'affiche originale et utilisé votre solution. Cependant maintenant mon typehinting ne le voit plus comme PDO. 'doit être une instance de PDO, instance de Mock_PDOMock_96936f72 donné' – nvanesch

2

Le mieux que je peux penser est d'utiliser runkit et redéfinir les deux méthodes finales protégées en utilisant runkit_function_redefine.

Ne pas avoir à activer le paramètre runkit.internal_override dans php.ini.

Et comme toujours, comme eval, si runkit semble que la réponse, la question est probablement mal :)

+0

Je ne pense pas qu'il y ait quelque chose de mal à utiliser 'runkit' ou' eval' à des fins de test. – netcoder

1

Vous instanciez votre scénario de test dans votre scénario de test?

$classToTest = new MyTest($pdoMock); 

À l'heure actuelle, vous testez essentiellement votre scénario de test. Cela devrait ressembler à quelque chose comme:

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

C'est certainement un bug dans la question originale. – uckelman