用于测试的 Symfony 模拟存储库

Posted

技术标签:

【中文标题】用于测试的 Symfony 模拟存储库【英文标题】:Symfony mocking repository for testing 【发布时间】:2021-09-01 00:21:06 【问题描述】:

我正在尝试模拟一个包含所有模块的存储库,它有一个名为 findAll() 的方法,该方法返回该存储库中的所有元素。我似乎无法从模拟存储库中提取任何数据。有什么想法可以解决吗?

模拟存储库:

$moduleRepository = $this->createMock(ModuleRepository::class);

尝试使用 ModuleRepository 类中名为 findAll() 的方法,该方法返回数组中 repo 中的所有元素。

$moduleRepository->expects($this->any())
        ->method('findAll')
        ->willReturn([]);

这就是我打印 $moduleRepository 时得到的:

Mock_ModuleRepository_f6bead1c Object
(
    [_entityName:protected] => 
    [_em:protected] => 
    [_class:protected] => 
    [__phpunit_originalObject:Mock_ModuleRepository_f6bead1c:private] => 
    [__phpunit_returnValueGeneration:Mock_ModuleRepository_f6bead1c:private] => 1
    [__phpunit_invocationMocker:Mock_ModuleRepository_f6bead1c:private] => PHPUnit\Framework\MockObject\InvocationHandler Object
        (
            [matchers:PHPUnit\Framework\MockObject\InvocationHandler:private] => Array
                (
                    [0] => PHPUnit\Framework\MockObject\Matcher Object
                        (
                            [invocationRule:PHPUnit\Framework\MockObject\Matcher:private] => PHPUnit\Framework\MockObject\Rule\AnyInvokedCount Object
                                (
                                    [invocations:PHPUnit\Framework\MockObject\Rule\InvocationOrder:private] => Array
                                        (
                                        )

                                )

                            [afterMatchBuilderId:PHPUnit\Framework\MockObject\Matcher:private] => 
                            [afterMatchBuilderIsInvoked:PHPUnit\Framework\MockObject\Matcher:private] => 
                            [methodNameRule:PHPUnit\Framework\MockObject\Matcher:private] => PHPUnit\Framework\MockObject\Rule\MethodName Object
                                (
                                    [constraint:PHPUnit\Framework\MockObject\Rule\MethodName:private] => PHPUnit\Framework\MockObject\MethodNameConstraint Object
                                        (
                                            [methodName:PHPUnit\Framework\MockObject\MethodNameConstraint:private] => findAll
                                            [exporter:PHPUnit\Framework\Constraint\Constraint:private] => 
                                        )

                                )

                            [parametersRule:PHPUnit\Framework\MockObject\Matcher:private] => 
                            [stub:PHPUnit\Framework\MockObject\Matcher:private] => PHPUnit\Framework\MockObject\Stub\ReturnStub Object
                                (
                                    [value:PHPUnit\Framework\MockObject\Stub\ReturnStub:private] => Array
                                        (
                                        )

                                )

                        )

                )

            [matcherMap:PHPUnit\Framework\MockObject\InvocationHandler:private] => Array
                (
                )

            [configurableMethods:PHPUnit\Framework\MockObject\InvocationHandler:private] => Array
                (
                    [0] => PHPUnit\Framework\MockObject\ConfigurableMethod Object
                        (
                            [name:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => findAllModuleRoutes
                            [returnType:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => SebastianBergmann\Type\SimpleType Object
                                (
                                    [name:SebastianBergmann\Type\SimpleType:private] => array
                                    [allowsNull:SebastianBergmann\Type\SimpleType:private] => 
                                    [value:SebastianBergmann\Type\SimpleType:private] => 
                                )

                        )

                    [1] => PHPUnit\Framework\MockObject\ConfigurableMethod Object
                        (
                            [name:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => findAllQueryBuilderWithSearch
                            [returnType:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => SebastianBergmann\Type\ObjectType Object
                                (
                                    [className:SebastianBergmann\Type\ObjectType:private] => SebastianBergmann\Type\TypeName Object
                                        (
                                            [namespaceName:SebastianBergmann\Type\TypeName:private] => Doctrine\ORM
                                            [simpleName:SebastianBergmann\Type\TypeName:private] => QueryBuilder
                                        )

                                    [allowsNull:SebastianBergmann\Type\ObjectType:private] => 
                                )

                        )

                    [2] => PHPUnit\Framework\MockObject\ConfigurableMethod Object
                        (
                            [name:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => findListResults
                            [returnType:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => SebastianBergmann\Type\SimpleType Object
                                (
                                    [name:SebastianBergmann\Type\SimpleType:private] => array
                                    [allowsNull:SebastianBergmann\Type\SimpleType:private] => 
                                    [value:SebastianBergmann\Type\SimpleType:private] => 
                                )

                        )

                    [3] => PHPUnit\Framework\MockObject\ConfigurableMethod Object
                        (
                            [name:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => createQueryBuilder
                            [returnType:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => SebastianBergmann\Type\UnknownType Object
                                (
                                )

                        )

                    [4] => PHPUnit\Framework\MockObject\ConfigurableMethod Object
                        (
                            [name:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => createResultSetMappingBuilder
                            [returnType:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => SebastianBergmann\Type\UnknownType Object
                                (
                                )

                        )

                    [5] => PHPUnit\Framework\MockObject\ConfigurableMethod Object
                        (
                            [name:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => createNamedQuery
                            [returnType:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => SebastianBergmann\Type\UnknownType Object
                                (
                                )

                        )

                    [6] => PHPUnit\Framework\MockObject\ConfigurableMethod Object
                        (
                            [name:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => createNativeNamedQuery
                            [returnType:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => SebastianBergmann\Type\UnknownType Object
                                (
                                )

                        )

                    [7] => PHPUnit\Framework\MockObject\ConfigurableMethod Object
                        (
                            [name:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => clear
                            [returnType:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => SebastianBergmann\Type\UnknownType Object
                                (
                                )

                        )

                    [8] => PHPUnit\Framework\MockObject\ConfigurableMethod Object
                        (
                            [name:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => find
                            [returnType:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => SebastianBergmann\Type\UnknownType Object
                                (
                                )

                        )

                    [9] => PHPUnit\Framework\MockObject\ConfigurableMethod Object
                        (
                            [name:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => findAll
                            [returnType:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => SebastianBergmann\Type\UnknownType Object
                                (
                                )

                        )

                    [10] => PHPUnit\Framework\MockObject\ConfigurableMethod Object
                        (
                            [name:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => findBy
                            [returnType:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => SebastianBergmann\Type\UnknownType Object
                                (
                                )

                        )

                    [11] => PHPUnit\Framework\MockObject\ConfigurableMethod Object
                        (
                            [name:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => findOneBy
                            [returnType:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => SebastianBergmann\Type\UnknownType Object
                                (
                                )

                        )

                    [12] => PHPUnit\Framework\MockObject\ConfigurableMethod Object
                        (
                            [name:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => count
                            [returnType:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => SebastianBergmann\Type\UnknownType Object
                                (
                                )

                        )

                    [13] => PHPUnit\Framework\MockObject\ConfigurableMethod Object
                        (
                            [name:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => __call
                            [returnType:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => SebastianBergmann\Type\UnknownType Object
                                (
                                )

                        )

                    [14] => PHPUnit\Framework\MockObject\ConfigurableMethod Object
                        (
                            [name:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => getClassName
                            [returnType:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => SebastianBergmann\Type\UnknownType Object
                                (
                                )

                        )

                    [15] => PHPUnit\Framework\MockObject\ConfigurableMethod Object
                        (
                            [name:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => matching
                            [returnType:PHPUnit\Framework\MockObject\ConfigurableMethod:private] => SebastianBergmann\Type\UnknownType Object
                                (
                                )

                        )

                )

            [returnValueGeneration:PHPUnit\Framework\MockObject\InvocationHandler:private] => 1
            [deferredError:PHPUnit\Framework\MockObject\InvocationHandler:private] => 
        )

)

我这样尝试过,该方法实际上被调用了,但是 repo 没有数据可供它查找。

$moduleRepository->expects($this->any())
        ->method('findAll')
        ->willReturn([]);
    $myDebugVar = $moduleRepository->findAll();
    fwrite(STDERR, print_r($myDebugVar, TRUE));

输出:

Array()

【问题讨论】:

调用方法findAll 将返回[]。它写在你的代码中。你还期待什么? @u_mulder 我正在尝试调用 ModuleRepository 具有的 findAll 方法,它将返回数组。我知道这个电话很糟糕,这就是为什么我要问如何让它变得更好。 返回什么数组? ModuleRepository 中所有模块的 @u_mulder。 Repository 有大约 30 个模块,我需要全部获取。 不要模拟 ModuleRepository。只需运行并执行查询。 【参考方案1】:

您的moduleRepository 将始终返回空数组,因为您说过要这样做。

这里你说返回一个空数组[]

->willReturn([]);

来自方法findAll

->method('findAll')

有一些方法可以处理它,但现在,我建议您创建一个仅用于测试目的的新数据库,然后创建一个新的 .env.test 文件,该文件将扩展原始 .env 文件并使用确切的存储库而不是模拟。

# .env.test.local
DATABASE_URL="mysql://USERNAME:PASSWORD@127.0.0.1:3306/DB_NAME?serverVersion=5.7"
namespace App\Tests\Repository;
use Doctrine\ORM\EntityManager;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;

final class SomeTest extends KernelTestCase

    private ?EntityManager $entityManager;

    protected function setUp(): void
    
        $kernel = self::bootKernel();

        $this->entityManager = $kernel->getContainer()
            ->get('doctrine')
            ->getManager();
    


    public function testSomething()
    
        //given
        $moduleRepository = $this->entityManager->getRepository(ModuleRepository::class);

        //when
        $result = $moduleRepository->findAll(...);

        //then
        $this->assertEquals(...);
    

    protected function tearDown(): void
    
        parent::tearDown();

        // doing this is recommended to avoid memory leaks
        $this->entityManager->close();
        $this->entityManager = null;
    

确保您将用数据填充一个新数据库。为自动执行此操作创建固定装置并在 tearDown 方法上清理数据库是个好主意。

【讨论】:

$this->moduleRepository = self::$container->get(ModuleRepository::class); 我收到这些错误:Incompatible types: Expected property of type '\App\Core\Repository\ModuleRepository', '\App\Core\Repository\ModuleRepository|null|object' provided 和这个:Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException: You have requested a non-existent service "monolog.handler.swift". @Kacper 我认为它应该类似于self::$container->getEntityManager()->getRepository(),我认为存储库未定义为服务。 是的,你是对的,谢谢@u_mulder。我将根据您的建议编辑我以前的帖子 Doctrine\Persistence\Mapping\MappingException: The class 'App\Core\Repository\ModuleRepository' was not found in the chain configured namespaces App\Core\Entity, App\Epa\Entity, App\Minerals\Entity, App\UserManagement\Entity, App\HrManagement\Entity, App\Calculator\Entity, App\Catalogue\Entity, App\CountryManagement\Entity, App\Cart\Entity, App\Inventory\Entity, App\Log\Entity, App\Prices\Entity, Gesdinet\JWTRefreshTokenBundle\Entity 程序为什么要在实体列表中寻找repository? 请告诉我您的存储库,我们的信息太少,无法为您提供正确答案。

以上是关于用于测试的 Symfony 模拟存储库的主要内容,如果未能解决你的问题,请参考以下文章

带有模拟存储库的 Nestjs 服务测试不起作用

在 symfony 4.4 的控制器中测试模拟服务

Symfony:在功能测试中模拟 LDAP 组件

Symfony 2.3 Bad Credentials 自定义提供程序

Symfony 5:/lucky/number 应用程序的 404 页面

单元测试如何使用 Mockito 模拟存储库