2012-04-12 26 views
24

Quiero utilizar Test Driven Development tanto como sea posible; es una excelente forma de trabajar.¿Cómo puedo probar la unidad de un controlador Symfony2?

Me preocupa el hecho de que los controladores Symfony2 creen y devuelvan un nuevo objeto Response.

Quiero ser capaz de probar la unidad de un controlador de forma aislada.

¿Cómo lo haces?

¿Es la respuesta para crear un controlador como un simple Objeto PHP sin formato, registrarlo como un servicio y usar Inyección de Dependencia para pasar un nuevo objeto Response (o una fábrica Response) en él?

+2

¿Cuál es exactamente el problema con que devolver un objeto 'Response'? –

+0

Nada. Simplemente no me gusta el hecho de que se crea un objeto Response en un controlador. Soy un firme creyente de Dependency Injection, y odio ver la palabra clave "nueva" en cualquier cosa que no sea un contenedor DI. Tal vez esa creencia es incorrecta. –

Respuesta

51

Normalmente, su controlador conecta diferentes objetos y los conecta en el orden correcto. Tal vez él llame a un repositorio, lea algunos objetos y los devuelva a través del método de renderizado. Tal vez él llama a otros Handlers/Managers que hacen cosas.

Esto significa que un controlador es un componente de alto nivel. En la mayoría de los casos, esto indica que las pruebas funcionales están en orden en lugar de las pruebas unitarias. No debe aspirar a obtener una cobertura de código del 100% con las pruebas de su unidad. Tal vez puedas pensarlo de esa manera: si tu unidad prueba todo lo que el controlador llama (modelo, validación, formulario, repositorio), ¿qué podría salir mal? La mayoría de las veces es algo que solo observas cuando usas todas las clases reales involucradas durante la producción.

También quiero señalar que TDD no significa que todo deba ser probado por la unidad. Está bien tener algunas pruebas funcionales para el código de alto nivel. Como se dijo, si prueba los componentes de bajo nivel con pruebas unitarias, solo debe probar cómo funcionan juntos, lo cual no puede probar con simulacros porque le dice a los simulacros cuál es el valor de retorno.

Si su controlador hace algo más que conectar partes del sistema, debería pensar en refaccionar el material en más clases de bajo nivel que pueda probar con pruebas unitarias.

Así que mi sugerencia es para utilizar pruebas funcionales para probar los controladores y utilizar pruebas unitarias para probar sus modelos y su lógica de negocios.

Si usted lucha con las pruebas funcionales, se puede leer lo siguiente:

+0

Bien. Pensé que dado que el Controlador era una clase, también necesitaba ser probado en una unidad. No me gusta la idea de escribir código antes de escribir pruebas, así que me preguntaba si había alguna manera de refactorizar la forma en que se usan los Controladores para poder probarlos en una unidad. Creo que todavía puedo trabajar con TDD escribiendo pruebas funcionales antes de escribir el controlador. –

2

Uso burla para aislar modelos y otros objetos de la lógica del método de controlador principal, consulte http://www.phpunit.de/manual/3.7/en/test-doubles.html#test-doubles.mock-objects

creo que en las versiones anteriores se podía burlarse de toda clase, pero con la última PHPUnit 3.6.10 que tengo no lo hace parece que funciona Así que supongo que se quedó con el patrón de inyección de dependencia

class objss{ 
    function ss(){ 
     $x = new zz(); 
     var_dump($x->z()); 
    } 
} 



class MoTest extends PHPUnit_Framework_TestCase{ 
    public function setUp(){ 

    } 

    public function testA(){ 
     $class = $this->getMock('zzMock', array('z'), array(), 'zz'); 
     $class->expects($this->any())->method('z')->will($this->returnValue('2')); 

     $obj = new objss(); 
     $this->assertEquals('2', $obj->ss()); 
    } 
} 
+0

Totalmente, pero estos objetos (incluido el objeto Response) se instanciarían en el Controlador. A menos que use el contenedor DI para proporcionar los modelos y otras cosas para los controladores. Tal vez podría crear un servicio de fábrica de Response y obtenerlo del contenedor DI, de esa forma (el contenedor DI y la fábrica) podría ser burlado para probar la clase Controller de forma aislada. –

0

Lewis - pensé que saltaría aquí. El enfoque anterior te permite replicar la mejor parte de la lógica de tus acciones en tus pruebas. No hay nada de malo en esto, muchos frameworks (notablemente RSPEC en Rails) realmente sugieren que se realicen tanto pruebas unitarias en sus objetos Controller como pruebas funcionales. Sin embargo, dado su ejemplo, creo que omitiría la prueba de la unidad y elegiría el enfoque funcional.

El objetivo de una prueba en mi mente es crear un entorno de espacio aislado, ejecutar la prueba y verificar los efectos secundarios y el resultado directo. Si llegas a un punto en el que la mayor parte de tu prueba está aislando el método, entonces es probable que sea hora de un enfoque de prueba diferente o un enfoque diferente para escribir tu clase. Dado que se trata de un controlador, y por naturaleza pegan diferentes piezas de la pila, creo su caja de arena más arriba en la pila. En concreto, me gustaría utilizar un enfoque como este:

https://github.com/PolishSymfonyCommunity/SymfonyMockerContainer

funcionó muy bien para mí :)

1

Unidad de Pruebas

Refactor sus controladores como servicios: http://symfony.com/doc/current/cookbook/controller/service.html

A continuación, fácilmente puede probarlos en una unidad.

Pruebas funcionales

Por supuesto (como ya se ha mencionado por otros) se puede utilizar el WebTestCase como se describe aquí: http://symfony.com/doc/current/book/testing.html#functional-tests

+0

La definición de controladores como servicios no está oficialmente recomendada por Symfony. Son utilizados por algunos desarrolladores para casos de uso muy específicos, como DDD (diseño impulsado por dominio) y aplicaciones de Arquitectura Hexagonal. –

+0

¿Quién dice eso? https://symfony.com/doc/current/controller/service.html El profesional tiene un peso superior al de la estafa en su propia documentación. Estoy bastante seguro de que los controladores serán compatibles con los servicios en las versiones futuras de Symfony, por lo que no me preocuparía demasiado porque "no se recomienda oficialmente". –

Cuestiones relacionadas