Тестирование Symfony FormType связано с EntityType

У меня вопрос к тестированию Symfony FormType. http://symfony.com/doc/current/cookbook/form/unit_testing.html

В моих типах типов тип entity является общим. Тестирование типов форм с типом формы объекта doctrine является ужасным.

Это мое поле формы.

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('products', 'entity', array(
        'class'     => 'AcmeDemoBundle:Product',
        'label'     => 'Product',
        'property'  => 'name',
        'required'  => false,
        'mapped'    => true,
        'multiple'  => true,
        'expanded'  => true
    ));
}

И вот макет для поля.

private function getEntityTypeMock()
{
    $entityRepositoryMock = $this->getMockBuilder('Doctrine\ORM\EntityRepository')
        ->disableOriginalConstructor()
        ->getMock()
    ;

    $entityRepositoryMock->expects($this->once())
        ->method('findAll')
        ->will($this->returnValue(array()));

    $classMetaDataMock = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')
        ->disableOriginalConstructor()
        ->getMock();

    $mockEntityManager = $this->getMockBuilder('Doctrine\ORM\EntityManager')
        ->disableOriginalConstructor()
        ->getMock();

    $mockEntityManager->expects($this->any())
        ->method('getClassMetadata')
        ->will($this->returnValue($classMetaDataMock));

    $mockEntityManager->expects($this->once())
        ->method('getRepository')
        ->will($this->returnValue($entityRepositoryMock));

    $mockRegistry = $this->getMockBuilder('Doctrine\Bundle\DoctrineBundle\Registry')
        ->disableOriginalConstructor()
        ->getMock();

    $mockRegistry->expects($this->any())
        ->method('getManagerForClass')
        ->will($this->returnValue($mockEntityManager));

    $mockEntityType = $this->getMockBuilder('Symfony\Bridge\Doctrine\Form\Type\EntityType')
        ->setMethods(array('getName'))
        ->setConstructorArgs(array($mockRegistry))
        ->getMock();

    $mockEntityType->expects($this->any())->method('getName')
        ->will($this->returnValue('entity'));

    return $mockEntityType;
}

Это действительно правильный способ? Внутри TypeTestCase у меня нет доступа ни к чему, никакого контейнера без ядра, ничего. Это делает тестирование типа формы довольно жестким и удручающим.

Есть ли лучший способ проверить типы форм? Или более простой способ борьбы с типами, которые имеют зависимость от ORM?

Приветствия.

Ответы

Ответ 1

Я боролся с модульной проверкой чего-то, что много полагается на контейнер услуг. Сначала я все время пытался насмехаться, как и ты. Это может сделать пропуск unit test с большим усилием (услуги имеют тенденцию полагаться на другие сервисы Symfony, которые также должны быть издевались), но требуется еще больше усилий, чтобы удостовериться, что передача теста означает, что это будет работать с данными, с которыми вы хотите работать.

Кроме того, модульное тестирование базы данных, как известно, сложно и редко обсуждается. Я не уверен, что то, что я использую, является "лучшим" ответом, но это ответ, который работал у меня, и это помогает unit test реальным услугам. Как таковой я нашел, что это более эффективный метод тестирования, чем насмехание сервисов.

Это основано на отличной статье, которую, конечно же, я не могу найти сейчас (я обновлю это, если найду это, чтобы отблагодарить их).

В принципе, вы можете настроить свои пакеты для тестирования контейнеров.

composer.json:

"require-dev": {
    "sensio/framework-extra-bundle": ">=3.0",
    "symfony/asset": ">=3.2"
}

Затем создайте config.yml с любыми услугами, которые могут вам понадобиться, и минимальным минимальным для форм Symfony:

framework:
    secret: 'shh'
    form: ~
    validation: { enable_annotations: true }
    session:
        storage_id: session.storage.mock_file

doctrine:
    # your doctrine settings if you want to test against the DB

Создайте класс AppKernel.

class AppKernel extends Kernel
{
    public function registerBundles()
    {
        return array(
            new FrameworkBundle(),
            new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
            // any other bundles you need
        );
    }

    public function registerContainerConfiguration(LoaderInterface $loader)
    {
        $loader->load(__DIR__.'/config.yml');

    }

    public function getLogDir()
    {
        return '/tmp/log/' . $this->environment;
    }
}

Наконец, я создаю вспомогательный класс в моей базе TestCase:

protected function getContainer()
{
    if (!isset($this->kernel)) {
        $this->kernel = new AppKernel('test', true);
        $this->kernel->boot();
    }
    if (!isset($this->container)) {
        $this->container = $this->kernel->getContainer();
    }
    return $this->container;
}

Теперь вы можете получить доступ к любым зарегистрированным вам службам:

public function testContainerAccess()
{
    $this->assertTrue(is_object($this->getContainer());
    $this->assertTrue($this->getContainer()->get('doctrine.orm.entity_manager') instanceof \Doctrine\ORM\EntityManagerInterface);
}

Тестирование по базе данных всегда сложно и представляет собой отдельную банку червей. В этом случае проще всего было бы создать отдельную схему тестирования и запустить ваши запросы против этого.

Надеюсь, что это поможет.