symfonytestingmockingsymfony6

Mock a repository request


I try to Mock a request to my database following these 2 guides and one SO question:

So I have this code:

   public static function kernelAndService(): array
    {
        $kernel = self::bootKernel(['environment' => 'test']);
        $mangaService = static::getContainer()->get(MangaService::class);
        $categoryRepository = static::getContainer()->get(CategoryRepository::class);

        return [
            [$kernel, $mangaService, $categoryRepository]
        ];
    }

   /**
     * Test utilisant un mockage de données
     * @dataProvider kernelAndService
     */
    public function testGetBestOfTwoMangasByCategoryMock(
        KernelInterface $kernel,
        MangaService $mangaService,
        CategoryRepository $categoryRepository
    ): void
    {
        // Boot du kernel pour accéder au container et déinir nos classes mockées
        $kernel->boot();
        $container = $kernel->getContainer();

        // Mockage de notre classe MangaRepository
        $mangaRepository = $this->createMock(MangaRepository::class);
        $mangaRepository->expects(self::any())->method('getBestOfThreeMangasByCategory')
            ->withAnyParameters()
            ->willReturn([
                new Manga(),
                new Manga(),
            ])
        ;

        // Mockage de l'entity manager pour lui passer notre repository
        $entityManager = $this->createMock(ManagerRegistry::class);
        $entityManager->expects(self::any())->method('getManager')->willReturn($entityManager);
        $entityManager->expects(self::any())->method('getRepository')
            ->withAnyParameters()
            ->willReturn($mangaRepository);

        $container->set(EntityRepository::class, $entityManager);
        $container->set(MangaRepository::class, $mangaRepository);

        $category = $categoryRepository->findOneBy(['name' => 'Ninja']);
        $mangas = $mangaService->getBestOfThreeMangasByCategory($category);

        assertCount(2, $mangas);
    }

Upon the assertion, I have this error message: Failed asserting that actual size 1 matches expected size 2.

In my mock, I created 2 mangas entity while I have one in database and after dumping the $mangas variable, I check that it contains the database result instead of the mocking expected result.

How can I mock my repository correctly ?

Symfony version, is 6.4.


Solution

  • I found the solution by getting my service again after setting the repository in the container. My service was initialized in the dataProvider with the non mocked MangaRepository in the constructor.

    // Mocking
    $mangaRepository = $this->createMock(MangaRepository::class);
    $mangaRepository->expects(self::any())->method('getBestOfThreeMangasByCategory')
            ->withAnyParameters()
            ->willReturn([
                new Manga(),
                new Manga(),
    ]);
    
    // Add mock repository to container 
    $container->set(MangaRepository::class, $mangaRepository);
    
    // Get a new service class initialized with mocked repository
    $mangaService = $container->get(MangaService::class);
    

    Then my reqest respond with my mocked result instead of the database result.