tutorial instalar español symfony

instalar - Symfony2: Comprobando las restricciones de validación de la entidad



symfony español (7)

Respuesta (b): Crear el Validador dentro de la Prueba Unitaria (Symfony 2.0)

Si construyó un Constraint y un ConstraintValidator , no necesita ningún contenedor DI.

Digamos, por ejemplo, que quiere probar la restricción de Type de Symfony y es TypeValidator . Simplemente puede hacer lo siguiente:

use Symfony/Component/Validator/Constraints/TypeValidator; use Symfony/Component/Validator/Constraints/Type; class TypeValidatorTest extends /PHPUnit_Framework_TestCase { function testIsValid() { // The Validator class. $v = new TypeValidator(); // Call the isValid() method directly and pass a // configured Type Constraint object (options // are passed in an associative array). $this->assertTrue($v->isValid(5, new Type(array(''type'' => ''integer'')))); $this->assertFalse($v->isValid(5, new Type(array(''type'' => ''string'')))); } }

Con esto puedes verificar todos los validadores que quieras con cualquier configuración de restricción. No necesita el ValidatorFactory ni el núcleo de Symfony.

Actualización: como señaló @psylosss, esto no funciona en Symfony 2.5. Tampoco funciona en Symfony> = 2.1. La interfaz de ConstraintValidator se modificó: isValid se renombró para validate y ya no devuelve un booleano. Ahora necesita una ExecutionContextInterface para inicializar un ConstraintValidator que necesita al menos una GlobalExecutionContextInterface y una TranslatorInterface ... Así que básicamente ya no es posible sin mucho trabajo.

¿Alguien tiene una buena manera de probar las restricciones de validación de una entidad en Symfony2?

Idealmente, quiero tener acceso al Contenedor de Inyección de Dependencia dentro de la prueba de la unidad que me daría acceso al servicio de validación. Una vez que tenga el servicio de validador, puedo ejecutarlo manualmente:

$errors = $validator->validate($entity);

Podría extender WebTestCase y luego crear un client para llegar al contenedor de acuerdo con los documentos, pero no se siente bien. WebTestCase y el client leen en los documentos como una herramienta más para probar acciones en conjunto y, por lo tanto, se siente interrumpido al usarlo para probar la unidad de una entidad.

Entonces, ¿alguien sabe cómo a) obtener el contenedor ob) crear el validador dentro de una prueba unitaria?


Con Symfony 2.8, parece que ahora puede usar la clase AbstractConstraintValidatorTest esta manera:

<?php namespace AppBundle/Tests/Constraints; use Symfony/Component/Validator/Tests/Constraints/AbstractConstraintValidatorTest; use AppBundle/Constraints/MyConstraint; use AppBundle/Constraints/MyConstraintValidator; use AppBundle/Entity/MyEntity; use Symfony/Component/Validator/Validation; class MyConstraintValidatorTest extends AbstractConstraintValidatorTest { protected function getApiVersion() { return Validation::API_VERSION_2_5; } protected function createValidator() { return new MyConstraintValidator(); } public function testIsValid() { $this->validator->validate(null, new MyEntity()); $this->assertNoViolation(); } public function testNotValid() { $this->assertViolationRaised(new MyEntity(), MyConstraint::SOME_ERROR_NAME); } }

Tienes una buena muestra con la clase IpValidatorTest


La respuesta en https://.com/a/41884661/4560833 tiene que cambiarse un poco para Symfony 4:

Use ConstraintValidatorTestCase lugar de AbstractConstraintValidatorTest .


Me gustó la respuesta de Kasheens, pero ya no funciona para Symfony 2.3. Hay pequeños cambios:

use Symfony/Component/Validator/Validation;

y

$validator = Validation::createValidatorBuilder()->getValidator();

Si quiere validar Anotaciones, por ejemplo, use enableAnnotationMapping () como se muestra a continuación:

$validator = Validation::createValidatorBuilder()->enableAnnotationMapping()->getValidator();

el resto permanece igual

$errors = $validator->validate($entity); $this->assertEquals(0, count($errors));


No veo un problema con la WebTestCase. Si no desea un cliente, no cree uno;) Pero si usa un servicio posiblemente diferente del que usará su aplicación real, esa es una potencial caída de pozo. Así que personalmente, he hecho esto:

class ProductServiceTest extends Symfony/Bundle/FrameworkBundle/Test/WebTestCase { /** * Setup the kernel. * * @return null */ public function setUp() { $kernel = self::getKernelClass(); self::$kernel = new $kernel(''dev'', true); self::$kernel->boot(); } public function testFoo(){ $em = self::$kernel->getContainer()->get(''doctrine.orm.entity_manager''); $v = self::$kernel->getContainer()->get(''validator''); // ... } }

Es menos DRY que la respuesta de Matt, ya que repetirá el código (para cada clase de prueba) y arrancará el kernel a menudo (para cada método de prueba), pero es autónomo y no requiere dependencias adicionales, por lo que depende de sus necesidades. . Además me deshice de la estática requiere.

Además, está seguro de tener los mismos servicios que usa su aplicación, no predeterminados o simulados, a medida que arranca el kernel en el entorno que desea probar.


Ok, ya que esto obtuvo dos votos, creo que otras personas están interesadas.

Decidí sacar mi pala y me sorprendió gratamente (hasta el momento, de todos modos) que esto no fuera del todo difícil de lograr.

Recordé que cada componente de Symfony2 se puede usar en un modo independiente y, por lo tanto, que yo mismo podría crear el validador.

Mirando los documentos en: https://github.com/symfony/Validator/blob/master/ValidatorFactory.php

Me di cuenta de que, dado que había una ValidatorFactory, era trivial crear un validador (especialmente para la validación hecha mediante anotaciones, pero si miras el docblock en la página que he vinculado anteriormente, también encontrarás formas de validar xml y yml )

Primero:

# Symfony >=2.1 use Symfony/Component/Validator/Validation; # Symfony <2.1 use Symfony/Component/Validator/ValidatorFactory;

y entonces:

# Symfony >=2.1 Validation::createValidatorBuilder()->enableAnnotationMapping()->getValidator(); # Symfony <2.1 $validator = ValidatorFactory::buildDefault()->getValidator(); $errors = $validator->validate($entity); $this->assertEquals(0, count($errors));

Espero que esto ayude a cualquier otra persona cuya conciencia no les permita usar WebTestCase;).


Terminamos haciendo rodar su propio caso de prueba base para acceder al contenedor de dependencia desde un caso de prueba. Aquí la clase en cuestión:

<?php namespace Application/AcmeBundle/Tests; // This assumes that this class file is located at: // src/Application/AcmeBundle/Tests/ContainerAwareUnitTestCase.php // with Symfony 2.0 Standard Edition layout. You may need to change it // to fit your own file system mapping. require_once __DIR__.''/../../../../app/AppKernel.php''; class ContainerAwareUnitTestCase extends /PHPUnit_Framework_TestCase { protected static $kernel; protected static $container; public static function setUpBeforeClass() { self::$kernel = new /AppKernel(''dev'', true); self::$kernel->boot(); self::$container = self::$kernel->getContainer(); } public function get($serviceId) { return self::$kernel->getContainer()->get($serviceId); } }

Con esta clase base, ahora puede hacer esto en sus métodos de prueba para acceder al servicio de validación:

$validator = $this->get(''validator'');

Decidimos ir con una función estática en lugar del constructor de la clase, pero podría cambiar fácilmente el comportamiento para instanciar el kernel en el constructor directamente en lugar de confiar en el método estático setUpBeforeClass proporcionado por PHPUnit.

Además, tenga en cuenta que cada método de prueba en su caso de prueba no se aislará uno del otro porque el contenedor se comparte para todo el caso de prueba. Hacer modificaciones en el contenedor puede tener un impacto en el otro método de prueba, pero este no debería ser el caso si solo tiene acceso al servicio de validator . Sin embargo, de esta forma, los casos de prueba se ejecutarán más rápido porque no necesitará crear instancias e iniciar un kernel nuevo para cada método de prueba.

En aras de la referencia, encontramos inspiración para esta clase en esta publicación de blog . Está escrito en francés, pero prefiero dar crédito a quién pertenece :)

Saludos,
Mate