PHPUnit тестирует защищенный статический метод, использующий pdo - PullRequest
0 голосов
/ 13 сентября 2018

Я очень новичок в 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 голосов
/ 18 сентября 2018

Следуя предложению Дормилича, я разработал интерфейс базы данных, на случай, если позже я решу, что не хочу использовать 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 был изменен следующим образом:

abstract class Model {
    protected $database=null;

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

Так что для тех, кто не знаком с внедрением зависимостей, я нашел следующие ссылки полезными:

http://php -di.org / документ / понимание-di.html https://codeinphp.github.io/post/dependency-injection-in-php/ https://designpatternsphp.readthedocs.io/en/latest/Structural/DependencyInjection/README.html

Надеюсь, это сокращает чью-то работу.

...