如何在PHPUnit中模拟MongoClient

时间:2014-09-09 22:53:10

标签: php mongodb unit-testing mocking phpunit

我正在重新设计一个应用程序,我选择使用TDD来完成它。我是TDD的新手,还没有爱上这个过程。目前,我遇到了一个问题,我无法找到任何明确的帮助。我可能只是过分思考,但肯定会感谢一些帮助,理解我遇到的问题。

我正在研究的项目仍然存在于MongoDB中。我已经和Mongo一起工作了一段时间并且很喜欢它,但PHP驱动程序似乎不适合我对如何(和什么)用假/模拟进行测试的有限理解。

这是一个示例类(我没有检查它是否会运行):

class UserCollection {
    protected $_mongo_client; //connection to persistence layer (MongoDB or mock)

    public function __construct($mongo_client, $id = NULL) {
        $this->_mongo_client = $mongo_client;
    }

    public function getUserInfo($mid) {
        $collection = $this->_mongo_client->vertical->primaryMember;
        $user = $collection->findOne(array('memberId' => intval($mid)), array('memberId'=> true, 'name'=>true,'stats' => true));

        if($user['memberId']) {
            $return['status'] = "Success";
            $return['user'] = $user;
        } else {
            $return['status'] = "Failure";
            $return['message'] = "User not found";
        }

        return $return;
    }
}

据我了解,如果我要先创建这个测试代码,我需要为数据库创建一个假 - 我一直试图想出一个模拟注入到构造函数中。如何创建处理如下行的模拟:

$collection = $this->_mongo_client->vertical->primaryMember;

我希望我只是在思考这个问题,并且有一种简单或更好的方法可以做到这一点。无论如何,我会很感激任何链接,圣人建议,或者对我的想法进行直接修正。

2 个答案:

答案 0 :(得分:2)

对于那些可能偶然发现这种情况的人,我找到了几个解决方案。在上面引用的案例中,我意识到将MongoCollection作为依赖项传递更为合适,而且这些很容易被模拟。

然而,当我使用Mockery作为我的模拟库时,有一些处理" Demeter链"的选项,就像我特别询问的那样:

$collection = $this->_mongo_client->vertical->primaryMember;

以下是文档的链接:

http://docs.mockery.io/en/latest/reference/demeter_chains.html

它基本上表明你理论上可以像这样模仿链:

$mock = \Mockery::mock('\MongoClient');
$mock->shouldReceive('vertical->primaryMember')->andReturn($mockMongoCollection);

你可以返回任何你想要的东西,而且看起来是一个非常可行的解决方案。

答案 1 :(得分:2)

另一个问题here也解决了这个问题。

Phactory为模拟MongoDB提供直接支持。 Here is a complete example中来自Phactory创作者的guide explaining how to mock MongoDB in PHP

修改:以上链接现已停止,而且Phactory似乎已不再维护。有一个名为`php-mongomock'的新项目旨在解决这个问题:

use Helmich\MongoMock\MockCollection;

$collection = new MockCollection();
$collection->createIndex(['foo' => 1]);

$documentId = $collection->insertOne(['foo' => 'bar'])->insertedId();
$collection->updateOne(['_id' => $documentId], ['$set' => ['foo' => 'baz']]);