Verspotten des PDO-Objekts mit PHPUnit

Lesezeit: 3 Minuten

Benutzer-Avatar
Ben Waine

Ich habe Schwierigkeiten, das PDO-Objekt mit PHPUnit zu verspotten.

Im Internet scheint es nicht viele Informationen zu meinem Problem zu geben, aber nach dem, was ich sammeln kann:

  1. PDO hat “finale” __wakeup- und __sleep-Methoden, die verhindern, dass es serialisiert wird.
  2. Die Mock-Objekt-Implementierung von PHPunit serialisiert das Objekt irgendwann.
  3. Die Unit-Tests schlagen dann mit einem von PDO generierten PHP-Fehler fehl, wenn dies auftritt.

Es gibt eine Funktion, die dieses Verhalten verhindern soll, indem Sie Ihrem Komponententest die folgende Zeile hinzufügen:

class MyTest extends PHPUnit_Framework_TestCase

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

}

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

Dies funktioniert bei mir nicht, mein Test erzeugt immer noch einen Fehler.

Vollständiger Testcode:

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

Helfen mir alle PHPUnit-Profis?

Vielen Dank,

Ben

  • Komisch, wie Leute das Debuggen ihres Codes debuggen. Ich bevorzuge es, den Code direkt zu debuggen und all diesen Unit-Testing-Müll in den Mülleimer zu werfen. Ich überlasse es Big Shots, die automatisierte Tests benötigen, weil ihre Anwendung so umfangreich ist, dass sie droht, von selbst zu einer unbemannten Mission zum Mars abzuheben.

    – JG Estiot

    5. Juli 2019 um 2:41 Uhr

$backupGlobals hilft Ihnen nicht weiter, da dieser Fehler woanders herkommt. PHPUnit 3.5.2 (möglicherweise auch frühere Versionen) hat den folgenden Code in 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']
          )
        );
    }

Dieser “Trick” mit Deserialize wird verwendet, wenn Sie getMock auffordern, den ursprünglichen Konstruktor nicht auszuführen, und es wird sofort mit PDO fehlschlagen.

Also, wie umgehen?

Eine Möglichkeit besteht darin, einen solchen Testhelfer zu erstellen

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

}

Das Ziel hier ist, den ursprünglichen PDO-Konstruktor loszuwerden, den Sie nicht benötigen. Ändern Sie dann Ihren Testcode wie folgt:

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

Schein wie diesen erstellen Wille ursprünglichen Konstruktor ausführen, aber da es jetzt dank mockPDO-Testhelfer harmlos ist, können Sie mit dem Testen fortfahren.

  • Du bist der Papa! Vielen Dank das funktioniert gut. Ich hatte es aufgegeben, dieses Problem zu lösen!

    – Ben Waine

    5. November 2010 um 22:30 Uhr

  • Ich hatte das gleiche Problem wie das Originalplakat und habe Ihre Lösung verwendet. Aber jetzt sieht mein Typehinting es nicht mehr als PDO. must be an instance of PDO, instance of Mock_PDOMock_96936f72 given

    – nvanesch

    11. April 2014 um 9:34 Uhr


  • @nvanesch scheint es auch nicht zu zählen instanceof \PDO, entweder. Am Ende habe ich nur die MockPDO-Klasse direkt instanziiert.

    – Soron

    25. September 2014 um 23:52 Uhr

Das Beste, was ich mir vorstellen kann, ist zu verwenden Runkit und definieren Sie die beiden letzten Methoden mit runkit_function_redefine als geschützt neu.

Vergessen Sie nicht, die Einstellung runkit.internal_override in php.ini zu aktivieren.

Und wie immer, wie bei eval, wenn Runkit die Antwort zu sein scheint, ist die Frage wahrscheinlich falsch 🙂

  • Ich denke nicht, dass bei der Verwendung etwas falsch ist runkit oder eval zu Testzwecken.

    – Netcoder

    3. November 2010 um 13:38 Uhr

Benutzer-Avatar
Netcoder

Sie instanziieren Ihren Testfall in Ihrem Testfall?

$classToTest = new MyTest($pdoMock);

Im Moment testen Sie im Wesentlichen Ihren Testfall. Es sollte eher so etwas sein wie:

$classToTest = new My($pdoMock);

  • Das ist definitiv ein Fehler in der ursprünglichen Frage.

    – uckelmann

    4. November 2010 um 19:18 Uhr

1187200cookie-checkVerspotten des PDO-Objekts mit PHPUnit

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy