如何在 Symfony 中为使用 queryBuilder 构建的 MongoDB 查询编写单元测试

Posted

技术标签:

【中文标题】如何在 Symfony 中为使用 queryBuilder 构建的 MongoDB 查询编写单元测试【英文标题】:How to write a unit test for MongoDB query built with queryBuilder in Symfony 【发布时间】:2022-01-16 01:36:04 【问题描述】:

我很难理解如何为这段代码编写单元测试

$qb = $documentManager->getRepository('Document:Account')->createQueryBuilder();
$qb->remove(\project\Document\Account::class)->field('username')
   ->equals($userAccount->getUsername())->getQuery()->execute();

这是我模拟这部分的尝试

$account = new account();
$documentAccount = $this->createMock(documentAccount::class);
$this->dm->expects($this->any())->method('getRepository')
     ->with($documentAccount)
     ->willReturn($account);

但当控件到达此部分时,我不断收到此错误。

提前谢谢你。

php 单元:PHPUnit 8.5.21

PHP:PHP 7.2.34

Symfony:Symfony 4.4.18

【问题讨论】:

【参考方案1】:

出现错误是因为你没有从$documentManager模拟,你的测试用例显然必须从它开始。

我曾经使用Prophecy 进行测试,但使用原生MockBuilder 是相同的逻辑。 考虑到我不知道你的用例使用的真实类,所以我让你大致了解你必须做什么,看看下面的代码:

    $queryBuilder = $this->createMock(QueryBuilder::class);
    $documentManager = $this->createMock(DocumentMannager::class);
    $documentAccount = $this->createMock(Document::Account);
    
    $documentManager
        ->expects($this->once())
        ->method('getRepository')
        ->with('Document:Account')
        ->willReturn($documentAccount)
    ;

    $documentAccount
        ->expects($this->once())
        ->method('createQueryBuilder')
        ->willReturn($queryBuilder)
    ;
    
    $queryBuilder
        ->expects($this->once())
        ->method('remove')
        ->with(\project\Document\Account::class)
        ->willReturn($queryBuilder)
    ;
    
    $queryBuilder
        ->expects($this->once())
        ->method('field')
        ->with('username')
        ->willReturn($queryBuilder)
    ;
    
    $queryBuilder
        ->expects($this->once())
        ->method('equals')
        ->withAnyParameters()
        ->willReturn($queryBuilder)
    ;
    
    $queryBuilder
        ->expects($this->once())
        ->method('getQuery')
        ->willReturn($queryBuilder)
    ;
    
    
    $queryBuilder
        ->expects($this->once())
        ->method('execute')
    ;

我们精确地模拟原始代码的每次调用

$qb = $documentManager->getRepository('Document:Account')->createQueryBuilder();
$qb->remove(\project\Document\Account::class)->field('username')
   ->equals($userAccount->getUsername())->getQuery()->execute();

【讨论】:

对不起,我忘了提到$documentManager 已通过测试为$this->dm 您在声明后没有在任何地方使用$documentManager。其次,您的意思是 $queryBuilder = $this->createMock(documentAccount::class); 吗?当你说$queryBuilder = $this->createMock(QueryBuilder::class); documentAccount 是Document:Account 谢谢 我编辑解决方案,因为我忘记了 $documentManager, 方法 ->createQueryBuilder() 的模拟,你必须检查什么是建立相应模拟的真正类,我不认为它是 documentAccount,不要不要忘记这是一个提案,因为我不知道你的全部代码。【参考方案2】:

这是我修复它的方法。这可能对遇到类似问题的人有所帮助

$accountDocumentRepo = $this->getMockBuilder(\project\Document\Account::class)
            ->disableOriginalConstructor()
            ->disableOriginalClone()
            ->disableArgumentCloning()
            ->disallowMockingUnknownTypes()
            ->setMethods(['remove','createQueryBuilder','field','equals','getQuery', 'execute'])
            ->getMock();

        $this->tradeDm->expects(self::any())->method('getRepository')->willReturn($accountDocumentRepo);

        $accountDocumentRepo->method('createQueryBuilder')->willReturn($accountDocumentRepo);
        $accountDocumentRepo->method('remove')->willReturn($accountDocumentRepo);
        $accountDocumentRepo->method('equals')->willReturn($accountDocumentRepo);
        $accountDocumentRepo->method('field')->willReturn($accountDocumentRepo);
        $accountDocumentRepo->method('getQuery')->willReturn($accountDocumentRepo);
        $accountDocumentRepo->method('execute')->willReturn($accountDocumentRepo);

【讨论】:

正如我在回答中提到的,您需要模拟所有调用的方法。

以上是关于如何在 Symfony 中为使用 queryBuilder 构建的 MongoDB 查询编写单元测试的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 LoginFormAuthenticator 和 Login Link Authenticator 在 Symfony 5.2 中为特定路径设置默认身份验证器

如何在 Symfony 中为 TimeType 添加约束

如何在循环symfony2中为同一实体添加重复的表单

Symfony 4:如何在防火墙中为用户/管理员提供多个提供者?

如何在 Symfony 2 中为数据库视图设置实体(原则)

在 Symfony 3 中为集合的每个元素应用特定的验证组