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?

图片转代码服务由CSDN问答提供 功能建议

对于练习我正在创建自己的数据库包装器和查询构建器。 创建 DatabaseConnection 对象时,会在此对象中创建一个新的PDO对象。

我有一个 Database 类,它取决于 DatabaseConnection 对象。 这个类构建查询并执行它们。

我的 DatabaseConnection 类如下所示:

< / p>

 使用PDO; 
 
class DatabaseConnection 
 {
 / ** 
 * @var PDO $ pdo PDO连接对象
 * / 
 private $ pdo; 
 \  n public function __construct(array $ credentials)
 {
#Logic with $ credentials to check on data 
 $ dsn = ...; 
#打开连接
 $ this-&gt; pdo = new \ PDO  ($ dsn,$ credentials ['username'],$ credentials ['password'],$ options); 
} 
 
 / ** 
 *检查连接是打开还是关闭
 * 
  * @return bool连接是打开还是关闭
 * / 
公共函数isConnected():bool 
 {
返回$ this-&gt; pdo!== null; 
} 
 
 / *  * 
 *检索PDO连接对象
 * 
 * @return PDO PDO连接对象
 * / 
公共函数getPDO():PDO 
 {
返回$ this-&gt; pdo; 
  } 
 
 / ** 
  *关闭连接
 * / 
公共函数__destruct()
 {
 $ this-&gt; pdo = null; 
} 
} 
   
 
 <  p>在测试时,我遇到了一个问题,即我总是需要在每台计算机上都有一个具有相同登录凭据的同名数据库我测试它。 
 
 

对于我的研究,我发现 我可以创建一个模拟对象,通过

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

这里的问题是我无法将 $ pdo 对象注入我的 DatabaseConnection class。

我做错了什么?如何在不使用实际数据库的情况下通过模拟数据来测试这个类?

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

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.

    点赞 打赏 评论

相关推荐 更多相似问题