kix

Примеси в PHP 5.4

Сегодня задался вопросом о том, почему мой проект на Symfony 2 все еще целится в PHP 5.3 как основную версию. Ну и предположил, что, вероятно, dev-часть можно смело переводить на 5.4 и использовать в тестах все специфичные для новой версии плюшки.

Начал я с трейтов, и нашел для них пока что как минимум одно хорошее применение: тесты.

Поскольку приложение симфонийское, постоянно приходится при запуске тестов этот самый контейнер доставать из static::createClient. Этот момент я реализовал в виде вот такой примеси:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
/**
 * WebTestCase client-aware test case
 */
trait ClientAware
{
    /**
     * @var \Symfony\Bundle\FrameworkBundle\Client
     */
    private $client;

    /**
     * Sets up client
     */
    public function setUp()
    {
        $this->client = static::createClient();
    }

    /**
     * @return \Symfony\Component\DependencyInjection\ContainerInterface
     */
    public function getContainer()
    {
        return $this->client->getContainer();
    }
}

Как можно заметить, я не стал здесь отступать от использования метода setUp(), чтобы PHPUnit меня правильно понял, и мне не пришлось в каждом тесте городить свой setUp() с блекджеком и вызовом метода вроде createClient(). Ну и поскольку контейнер тоже приходится получать довольно часто, я вывел еще и шорткат-метод для этой самой цели.

А еще почти что во всех тестах, связанных с моделями, приходится очищать БД в методе setUp(). Однако это довольно-таки много кода, и остается либо вынести всю логику в класс-наследник WebTestCase, или копипастить код. Меня такое решение не устроило, и я решил, что тут не помешает трейт:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
use \Doctrine\Common\DataFixtures;

/**
 * Purges DB, needs container
 */
trait PurgeDb
{

    use ClientAware {
        setUp as clientAwareSetUp;
    }

    /**
     * Calls ClientAware trait method
     */
    public function setUp()
    {
        $this->clientAwareSetUp();

        $em = $this->getContainer()->get('doctrine.orm.entity_manager');
        $purger = new DataFixtures\Purger\ORMPurger($em);
        $purger->purge();
    }

}

Тут надо обратить внимание на строчки 9-11. В них конструкция, которая позволяет одной примеси включить в себя другую в случае, когда их имена методов совпадают. И поскольку в PurgeDb мне однозначно нужен контейнер, я вызываю метод ClientAware::setUp().

Дальше все достаточно очевидно: поскольку контейнер у меня уже есть, я могу смело достать из него Entity Manager и скормить его в Purger, который затем чистит мою БД.

А теперь, собственно, как все это использовать? Вот тест, которому перед запуском нужна пустая база:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
use \Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

use PurgeDb;

class FakerTest extends WebTestCase
{

    use PurgeDb;

    public function testPurgeAndPopulateEntity()
    {
        /** @var $em \Doctrine\ORM\EntityManager */
        $em = $this->getContainer()->get('doctrine.orm.entity_manager');
        $this->assertEquals(
            0,
            count($em->getRepository('WtProMainBundle:User')->findAll())
        );

        $faker = new \My\Faker($this->getContainer());

        $populator = $faker->getPopulator();
        $populator->addEntity('Entity\User', 3);
        $populator->execute(
            $this->getContainer()->get('doctrine.orm.entity_manager')
        );

        $this->assertEquals(
            3,
            count($em->getRepository('WtProMainBundle:User')->findAll())
        );
    }
}

Как можно заметить, метод setUp() в нем вообще отсутствует. А поскольку PurgeDb не только чистит БД, но и вызывает setUp() из ClientAware, в моем тесте я могу всегда получить контейнер легко и непринужденно.

comments powered by Disqus