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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PHPUnit测试使用pdo的受保护静态方法相关的知识,希望对你有一定的参考价值。

我对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 PHPUnitFrameworkTestCase;

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的调用。

答案

根据Dormilich的建议,我开发了一个数据库界面,以防我后来决定不想使用PDO。

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

接下来,我为构造函数编写了测试。我使用setup来确保我开始使用 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修改如下:

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

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

以上是关于PHPUnit测试使用pdo的受保护静态方法的主要内容,如果未能解决你的问题,请参考以下文章

使用 PHPUnit 测试受保护方法的最佳实践

使用 PHPUnit 模拟 PDO 对象

静态方法的受保护修饰符的目的是啥

PHP 从静态方法访问对象的受保护属性

PHP单元测试,带模拟的受保护方法

使用 Java 反射访问测试用例中的受保护方法