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:

  1. PDO a 'final' _ _ wakeup et _Méthodes _sleep qui l'empêchent d'être sérialisé.
  2. l'implémentation d'objet fictif 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 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

33
demandé sur Galen 2010-06-29 12:19:04

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.

47
répondu Anti Veeranna 2010-11-02 22:23:36

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:)

2
répondu omarshariffdontlikeit 2010-06-29 09:43:15

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);
1
répondu netcoder 2013-09-18 05:42:35