在Symfony应用程序中用PHPUnit测试回滚Doctrine DataFixture变化

72 阅读1分钟

在这个例子中,我们要回滚对数据库中的数据所做的修改,这样我们就不必为每个测试重新加载Doctrine DataFixtures。这将提高测试性能,因为我们只在整个测试套件开始时加载一次DataFixtures,并在每个测试案例后回滚任何更改。因此,我们的测试不会中断,即使他们都依赖于相同的数据。

declare(strict_types=1);

namespace App\Tests;

use App\DataFixtures\CountryFixtures;
use Doctrine\Common\DataFixtures\Executor\ORMExecutor;
use Doctrine\Common\DataFixtures\Loader;
use Doctrine\Common\DataFixtures\Purger\ORMPurger;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Client;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class AbstractTest extends WebTestCase
{
    /** @var Client $client */
    protected $client;
    /** @var EntityManagerInterface */
    private $entityManager;

    public static function setUpBeforeClass()
    {
        $kernel = static::createKernel();
        $kernel->boot();
        $entityManager = $kernel->getContainer()->get('doctrine')->getManager();

        $loader = new Loader();
        foreach (self::getFixtures() as $fixture) {
            $loader->addFixture($fixture);
        }

        $purger = new ORMPurger();
        $purger->setPurgeMode(ORMPurger::PURGE_MODE_DELETE);
        $executor = new ORMExecutor($entityManager, $purger);
        $executor->execute($loader->getFixtures());
    }

    protected function setUp()
    {
        $this->client = static::createClient();
        $this->client->disableReboot();

        $this->entityManager = $this->client->getContainer()->get('doctrine.orm.entity_manager');
        $this->entityManager->beginTransaction();
        $this->entityManager->getConnection()->setAutoCommit(false);
    }

    protected function tearDown()
    {
        if ($this->entityManager->getConnection()->isTransactionActive()) {
            $this->entityManager->rollback();
        }
    }

    private static function getFixtures(): iterable
    {
        return [
            new CountryFixtures(),
        ];
    }
}

Great Britain 下面的update_one 方法实际上改变了数据库中codename 记录的值。我只是使用了GET 方法,以使这个例子尽可能的简短,达到演示的目的。在后台,code 被改变为abcname 被改变为Hello 。正如你在下面的测试结果中所看到的,get_all_returns_valid_response_2 并没有被破坏!

declare(strict_types=1);

namespace App\Tests\Controller;

use App\Tests\AbstractTest;

class CountryControllerTest extends AbstractTest
{
    /**
     * @test
     * @dataProvider getAllDataProvider
     */
    public function get_all_returns_valid_response_1(int $code, string $body): void
    {
        $this->client->request('GET', '/api/v1/countries');

        $this->assertSame($code, $this->client->getResponse()->getStatusCode());
        $this->assertSame($code, $this->client->getResponse()->getStatusCode());
        $this->assertSame($body, $this->client->getResponse()->getContent());
    }

    /**
     * @test
     */
    public function update_one(): void
    {
        $this->client->request('GET', '/api/v1/countries/1');

        $this->assertSame(200, $this->client->getResponse()->getStatusCode());
    }

    /**
     * @test
     * @dataProvider getAllDataProvider
     */
    public function get_all_returns_valid_response_2(int $code, string $body): void
    {
        $this->client->request('GET', '/api/v1/countries');

        $this->assertSame($code, $this->client->getResponse()->getStatusCode());
        $this->assertSame($body, $this->client->getResponse()->getContent());
    }

    public function getAllDataProvider(): iterable
    {
        return [
            [
                '$code' => 200,
                '$body' => <<[
  {
    "id": 1,
    "code": "gb",
    "name": "Great Britain",
  },
  {
    "id": 2,
    "code": "tr",
    "name": "Turkey",
  },
  {
    "id": 3,
    "code": "de",
    "name": "Germany",
  }
]
EOT
            ]
        ];
    }
}

测试

$ vendor/bin/phpunit --filter CountryControllerTest tests/Controller/CountryControllerTest.php 
PHPUnit 7.1.5 by Sebastian Bergmann and contributors.

...                           3 / 3 (100%)

Time: 592 ms, Memory: 12.00MB

OK (3 tests, 5 assertions)