Se moquer de L'objet PDO en utilisant PHPUnit
J'ai du mal à me moquer de L'objet PDO avec PHPUnit.
Il ne semble pas y avoir beaucoup d'informations sur le web sur mon problème, mais à partir de ce que je peux rassembler:
- PDO a 'final' _ _ wakeup et _Méthodes _sleep qui l'empêchent d'être sérialisé.
- l'implémentation d'objet fictif de PHPunit sérialise l'objet à un moment donné.
- les tests unitaires échouent alors avec une erreur PHP générée par PDO lorsque cela se produit.
Il y a une fonctionnalité destinée à empêchez 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
Cela ne fonctionne pas pour moi, mon test produit toujours une erreur.
Code de 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.......
Un PHPUnit pro me donne un coup de main?
Merci,
Ben
3 réponses
$ backupGlobals ne vous aide pas, car cette erreur vient d'ailleurs. PHPUnit 3.5.2 (peut-être aussi des versions antérieures) a le code suivant dans PHPUnit/Framework/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']
          )
        );
    }
Cette "astuce" avec unserialize est utilisée lorsque vous demandez à getMock de ne pas exécuter le constructeur d'origine et elle échouera rapidement avec PDO.
Alors, comment le contourner?
Une option consiste à créer un assistant de test comme celui-ci
class mockPDO extends PDO
{
    public function __construct ()
    {}
}
Le but ici est de se débarrasser du constructeur PDO d'origine, dont vous n'avez pas besoin. Ensuite, changez votre code de test en ceci:
$pdoMock = $this->getMock('mockPDO', array('prepare'));
Créer un mock comme celui-ci exécutera constructeur original, mais comme il est maintenant inoffensif grâce à mockpdo test helper, vous pouvez continuer à tester.
Le mieux que je puisse penser est d'utiliser runkit et de redéfinir les deux méthodes finales protégées en utilisant runkit_function_redefine.
Dont POUR get pour activer le runkit.paramètre internal_override en php.ini.
Et comme toujours, comme avec eval, si runkit semble être la réponse, la question est probablement fausse:)
Vous instanciez votre cas de test dans votre cas de test?
$classToTest = new MyTest($pdoMock);
En ce moment, vous testez essentiellement votre cas de test. Il devrait être plus quelque chose comme:
$classToTest = new My($pdoMock);