douxunchen3498 2017-06-17 13:15
浏览 57
已采纳

在PHPUnit中模拟紧密耦合的对象

For practice i'm creating my own database wrapper and query builder. When creating a DatabaseConnection object, a new PDO object is created in this object.

I have a Database class which depends on the DatabaseConnection object. This class builds the queries and executes them.

My DatabaseConnection class looks like this:

use PDO;

class DatabaseConnection
{
    /**
     * @var PDO $pdo The PDO connection object
     */
    private $pdo;

    public function __construct(array $credentials)
    {
        # Logic with $credentials to check on data
        $dsn = ...;
        # Open the connection
        $this->pdo = new \PDO($dsn, $credentials['username'], $credentials['password'], $options);
    }

    /**
     * Checks whether the connection is open or closed
     *
     * @return bool Whether the connection is open or closed
     */
    public function isConnected() : bool
    {
        return $this->pdo !== null;
    }

    /**
     * Retrieves the PDO connection object
     *
     * @return PDO The PDO connection object
     */
    public function getPDO() : PDO
    {
        return $this->pdo;
    }

    /**
     * Closes the connection
     */
    public function __destruct()
    {
        $this->pdo = null;
    }
}

When testing this, I ran across the problem that I always have to have a indentical database with the same login credentials on every computer i test this on.

For my research, I found out that I can create a mock objects, by doing

$pdo = $this->getMockBuilder('PDO')
    ->disableOriginalConstructor()
    ->getMock();

The problem here is that I can't inject the $pdo object into my DatabaseConnection class.

What am I doing wrong and how can I test this class without using an actual database by mocking data?

  • 写回答

1条回答 默认 最新

  • doutou6803 2017-06-17 13:25
    关注

    For your mock, create a subtype of the DatabaseConnection, override the constructor and make the PDO object injectable. Then you can mock the PDO object and create the full mock for mocking operations.

    Having "news" inside a constructor is a smell btw., your constructor should not do real work.

    As you have found out while testing, this makes your type hard to test. Creating a mock on your own (by writing it out) can lighten up the darkened sky.

    You might also not want to initialize the resources early, but connect to the database as late as possible. This would also move the new out of the constructor.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 delta降尺度计算的一些细节,有偿
  • ¥15 Arduino红外遥控代码有问题
  • ¥15 数值计算离散正交多项式
  • ¥30 数值计算均差系数编程
  • ¥15 redis-full-check比较 两个集群的数据出错
  • ¥15 Matlab编程问题
  • ¥15 训练的多模态特征融合模型准确度很低怎么办
  • ¥15 kylin启动报错log4j类冲突
  • ¥15 超声波模块测距控制点灯,灯的闪烁很不稳定,经过调试发现测的距离偏大
  • ¥15 import arcpy出现importing _arcgisscripting 找不到相关程序