0

I have a command which runs over the database, then tests if any companies have a duplicate name, then outputs to the user for any remediation.

What I want to do for each test is:

  • Change the database to prescribed set of companies, e.g. 10 companies with 5 of those having duplicate names or e.g. 10 companies with 5 having null names
  • Run that test

Normally if this was a function, I could use a data provider in the annotation to provide different data to test e.g.

     * @dataProvider provideFoo
     * @param $data
     */
    public function testFooBar($data) {...

But the command has no args/params, so I think I have to update the database each time.

Can this be done with fixtures, or should I add new companies in each test e.g.:

public function testFooBar($data) {
  $company1 = (new Company())->setName('Company 1');
  $this->entityManager->persist($company1);
  $this->entityManager->flush();
  
  $commandTester->execute([]);
  // rest of test
}

I should add - the db is quite large and dropping it and resetting it takes a few hours.

** Edit ** I found this question, which seems to have helped me set up the test database, I will carry on to see if I can get fixtures working now the test database is up: How to setup a database for test environment in Symfony 4

Leon Segal
  • 679
  • 7
  • 28

1 Answers1

0

I managed to get it working using this:

// tests/Command/FindDuplicatedCompaniesCommandTest.php:
<?php declare(strict_types=1);

namespace App\Tests\Command;

use App\DataFixtures\DuplicatedCompaniesFixtures;
use App\Tests\FixturesTrait;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Console\Tester\CommandTester;

class FindDuplicatedCompaniesCommandTest extends KernelTestCase
{
    use FixturesTrait;

    public function testExecuteDuplicates()
    {
        $kernel = static::createKernel();
        $application = new Application($kernel);
        $command = $application->find('app:find:duplicated-companies');
        $commandTester = new CommandTester($command);

        $this->addFixture(new DuplicatedCompaniesFixtures());
        $this->executeFixtures();

        $commandTester->execute([]);

        $output = $commandTester->getDisplay();

        $this->assertStringContainsString('Detected name', $output);
        $this->assertStringContainsString('Company 3', $output);
        $this->assertStringContainsString('Company 1', $output);
        $this->assertStringNotContainsString('violations', $output);
        $this->assertStringNotContainsString('No duplicates', $output);
    }

    protected function setUp(): void
    {
        self::bootKernel();
    }
}

// src/DataFixtures/DuplicatedCompaniesFixtures.php
<?php declare(strict_types=1);

namespace App\DataFixtures;

use App\Entity\Company;
use DateTimeImmutable;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;

/**
 * Class DuplicatedCompaniesFixtures
 * @package App\DataFixtures
 */
class DuplicatedCompaniesFixtures extends Fixture
{
    /**
     * @const CO_1_REFERENCE
     */
    public const CO_1_REF = 'COONE';

    /**
     * @const CO_2_REFERENCE
     */
    public const CO_2_REF = 'COTWO';

    /**
     * @const CO_3_REFERENCE
     */
    public const CO_3_REF = 'COTHREE';

    /**
     * @const CO_4_REFERENCE
     */
    public const CO_4_REF = 'COFOUR';

    /**
     * @param ObjectManager $manager
     */
    public function load(ObjectManager $manager)
    {
        $company1 = (new Company())
            ->setName('Company 1')
            ->setAlphaKey('COMPANYONE')
            ->setUpdatedAt(new DateTimeImmutable());
        $company2 = (new Company())
            ->setName('Company 1')
            ->setAlphaKey('COMPANYONE')
            ->setUpdatedAt(new DateTimeImmutable());
        $company3 = (new Company())
            ->setName('Company 3')
            ->setAlphaKey('COMPANYTHREE')
            ->setUpdatedAt(new DateTimeImmutable());
        $company4 = (new Company())
            ->setName('Company 3')
            ->setAlphaKey('COMPANYFOUR')
            ->setUpdatedAt(new DateTimeImmutable());

        $manager->persist($company1);
        $manager->persist($company2);
        $manager->persist($company3);
        $manager->persist($company4);
        $manager->flush();
        $this->addReference(self::CO_1_REF, $company1);
        $this->addReference(self::CO_2_REF, $company2);
        $this->addReference(self::CO_3_REF, $company3);
        $this->addReference(self::CO_4_REF, $company4);
    }
}

That way, I can add a different fixture per test in a file, so e.g. if I wanted a separate test for name violations, I would add src/DataFixtures/NameViolationCompaniesFixtures.php and call it in the test.

Leon Segal
  • 679
  • 7
  • 28