PHPUnit测试使用pdo的受保护静态方法

时间:2018-09-13 20:19:01

标签: pdo phpunit

我对TDD非常陌生。我正在使用phpunit 7.4x-dev。我有下面的抽象类,我正在尝试为其开发单元测试。

use PDO;

abstract class Model {

    protected static function getDB() {
        static $db = null;
        if ($db === null) {

                $db = new PDO(ConfigDatabase::DSN, ConfigDatabase::USER, ConfigDatabase::PASSWORD);
                $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        }
        return $db;
    }


}

我创建了以下测试来解决需要处理静态保护方法的问题。如果我提供“ ConfigureDatabase”类,它将起作用。

use PHPUnit\Framework\TestCase;

class ModelTest extends TestCase {

    function newMockClass(){
        $stub = new class() extends Model{
            function getStaticMethod($methodName){
                return self::$methodName();
            }
        };        
        return $stub;

    }

    public function testDatabaseExists() {
         $stub = $this->newMockClass();
         $db = $stub->getStaticMethod('getDB');
         $this->assertInstanceOf(PDO::class,$db);         
    }

}

由于我不想我的测试依赖于任何实际的数据库,因此我该如何伪造对PDO的调用。

1 个答案:

答案 0 :(得分:0)

按照Dormilich的建议,我开发了一个数据库接口,以防万一我以后决定不使用PDO。

interface CRUDImp {
    function __construct($datbaseBridgeLikePDO);
    ...
}

接下来,我为构造函数编写了测试。我使用设置来确保我从全新的\ PDO模拟开始。

    class PDOWrapperTest extends TestCase {
    private $pdoMock;
    private $db;

    function setup() {
        $this->pdoMock = $this->createMock('\PDO');
        $this->db = new PDOWrapper($this->pdoMock);
    }

        public function testWrapperExists() {
            $this->pdoMock->method('getAttribute')->willReturn(\PDO::ERRMODE_EXCEPTION);

            $db = new PDOWrapper($this->pdoMock);
            $x = $db instanceof CRUDImp;

            $this->assertTrue($x);
        }

        /**
         * @expectedException \Exception
         */
        public function testNonPDOPassedToConstructor() {
            $mock = $this->createMock('\Exception');
            $x = new PDOWrapper($mock);
        }
    ...
    }

由于PHP是松散类型的,所以我检查以确保传递给构造函数的类是\ PDO的实例。我按如下方式实现了具体的课程

class PDOWrapper implements CRUDImp {

    private $pdo;
    private $dataOutputType = \PDO::FETCH_ASSOC;

    public function __construct($pdo) {

        if (!($pdo instanceof \PDO)) {
            throw new \Exception("PDOWrapper must be passed instance of \PDO");
        }

        $attr_Errmode = $pdo->getAttribute(\PDO::ATTR_ERRMODE);
        if ($attr_Errmode !== \PDO::ERRMODE_EXCEPTION) {
            $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
        }
        $this->pdo = $pdo;
    }
...
}

现在,我有了一个独立的数据库包装程序,原始的Model测试现在变得微不足道了,不再需要了。对抽象类Model的修改如下:

abstract class Model {
    protected $database=null;

    function __construct(CRUDWrapper $database) {
        $this->database = $database;
    }
...
}

对于那些不熟悉依赖注入的人,我发现以下链接很有帮助:

http://php-di.org/doc/understanding-di.html https://codeinphp.github.io/post/dependency-injection-in-php/ https://designpatternsphp.readthedocs.io/en/latest/Structural/DependencyInjection/README.html

希望这会缩短某人的工作时间。