Home > database >  Symfony PHPunit Testing - how do I mock services?
Symfony PHPunit Testing - how do I mock services?

Time:08-04

I'm just wondering how you'd mock a service in Symfony.

This is what I've ended up with so far and it's not working as expected. I expect the getVenuesData() method from the NetballFeedService to dump the mocked data in the test (I've set a DD in the command). But when I run the test, it dumps the real time data being pulled from the NetballFeedService.

Test:

    public function it_imports_venues(): void
    {
        $kernel = self::bootKernel();

        $netballAPIMock = $this->createMock(NetballFeedService::class);
        $netballAPIMock->method('getVenuesData')->willReturn([
            800 => ['name' => 'Venue 1', 'location' => 'MEL'],
            801 => ['name' => 'Venue 2', 'location' => 'ADE']
        ]);

        $this->getContainer()->set('netballAPI', $netballAPIMock);

        $container = $kernel->getContainer();
        $container->set('netballAPI', $netballAPIMock);

        $application = new Application($kernel);

        $command = $application->find('app:feed:import-venues');
        $commandTester = new CommandTester($command);
        $commandTester->execute([]);
        $commandTester->assertCommandIsSuccessful();
    }

Command being tested:

    protected static $defaultName = 'app:feed:import-venues';

    public function __construct(
        private readonly NetballFeedService $netballFeedService,
        private readonly VenueService $venueService
    )
    {
        parent::__construct();
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $data = $this->netballFeedService->getVenuesData();
        dd($data);
        $this->venueService->updateVenuesDataFromFeed($data);

        return 0;
    }

Class method expected to return mocked data:

    public function getVenuesData(): array
    {
        $response = $this->client->request('GET', self::FIXTURES_URL);
        $rawData = json_decode($response->getBody()->getContents(), true);
        $rounds = $rawData['data']['results'];

        $parsedVenuesData = [];
        foreach ($rounds as $round) {
            foreach ($round['matches'] as $matches) {
                $venueId = $matches['venueId'];

                if (array_key_exists($venueId, $matches)) {
                    continue;
                }

                $parsedVenuesData[$matches['venueId']] = [
                    'name' => $matches['venueName'],
                    'location' => $matches['venueLocation']
                ];
            }
        }

        ksort($parsedVenuesData);

        return $parsedVenuesData;
    }

I'm trying to replicate my Laravel test code in Symfony:

/** @test */
    public function it_imports_venues()
    {
        $this->withExceptionHandling();

        $this->instance(
            NetballAPI::class,
            Mockery::mock(NetballAPI::class, function (MockInterface $mock) {
                $mock->shouldReceive('getVenuesData')->once()
                    ->andReturn([
                        800 => [
                            'name' => 'Venue 1',
                            'location' => 'MEL'
                        ],
                        801 => [
                            'name' => 'Venue 2',
                            'location' => 'ADE'
                        ],
                    ]);
            })
        );

        $this->artisan('import:venues');

        $this->assertDatabaseHas('venues', [
            'id' => 800,
            'name' => 'Venue 1',
            'location' => 'MEL'
        ]);

        $this->assertDatabaseHas('venues', [
            'id' => 801,
            'name' => 'Venue 2',
            'location' => 'ADE'
        ]);

services_test.yml:

services:
  _defaults:
    public: true

  App\Service\NetballFeedService:
    public: true
    alias: netballAPI

Just wondering how I can mock the NetballFeedService class in the test instance? Thanks in advance.

CodePudding user response:

I was configuring the service_test.yaml wrong. It should be:

services:
  App\Service\NetballFeedService:
    public: true

  app.netballFeedService:
    alias: App\Service\NetballFeedService
    public: true

Also, I'm not really used to using YAML files for configs. It's not very readable especially compared to it's PHP file counterpart in this instance. So I'll be experimenting on using both YAML & PHP files for configs/routes etc.

  • Related