Laravel, BDD y tú Comencemos

Bienvenido a esta serie sobre el desarrollo de aplicaciones Laravel utilizando un enfoque de desarrollo basado en el comportamiento (BDD). El BDD de pila completa puede parecer complicado e intimidante. Hay tantas formas de hacerlo como desarrolladores.. 

En esta serie, lo guiaré a través de mi enfoque de usar Behat y PhpSpec para diseñar una aplicación Laravel desde cero.

Hay muchos recursos en BDD en general, pero el material específico de Laravel es difícil de encontrar. Por lo tanto, en esta serie, nos centraremos más en los aspectos relacionados con Laravel y menos en las cosas generales que puedes leer sobre muchos otros lugares..

Describiendo el comportamiento

Al describir el comportamiento, que también se conoce como escribir historias y especificaciones, usaremos un enfoque de afuera hacia adentro. Esto significa que cada vez que creamos una nueva característica, comenzaremos escribiendo la historia general del usuario. Esto es normalmente desde la perspectiva de los clientes o partes interesadas.. 

¿Qué esperamos que suceda cuando hacemos esto?? 

No se nos permite escribir ningún código hasta que tengamos un paso rojo fallando, por ejemplo, a menos que estemos refactorizando el código existente. 

A veces, será necesario resolver de manera iterativa una pequeña parte de una historia o característica (dos palabras que uso indistintamente) en las que estamos trabajando. Esto a menudo significará escribir especificaciones con PhpSpec. A veces tomará muchas iteraciones en un nivel de integración o unidad antes de que pase toda la historia (en un nivel de aceptación). Todo esto suena muy complicado pero realmente no lo es. Soy un gran creyente de aprender haciendo, así que creo que todo tendrá más sentido una vez que comencemos a escribir un código real..

Estaremos escribiendo historias y especificaciones en cuatro niveles diferentes:

1. Aceptación

La mayoría de las veces, nuestra suite funcional servirá como nuestra capa de aceptación. La forma en que describiremos nuestras funciones en nuestra suite funcional será muy similar a la forma en que escribiríamos historias de aceptación (utilizando un marco de navegador automatizado) y, como tal, crearía mucha duplicación.. 

Mientras las historias describan el comportamiento desde el punto de vista del cliente, sirven como historias de aceptación. Usaremos Symfony DomCrawler para probar el resultado de nuestra aplicación. Más adelante en la serie, podríamos encontrar que necesitamos probar a través de un navegador real que también puede ejecutar JavaScript. La prueba a través del navegador agrega algunas preocupaciones nuevas, ya que necesitamos asegurarnos de que cargamos el entorno de prueba de una hora cuando se ejecuta la suite.

2. Funcional

En nuestra suite funcional, tendremos acceso a la aplicación Laravel, que es muy conveniente. En primer lugar, facilita la diferenciación entre entornos. En segundo lugar, no utilizar un navegador hace que nuestra suite de pruebas sea mucho más rápida. Cada vez que queramos implementar una nueva función, escribiremos una historia en nuestra suite funcional usando Behat.

3. Integración

Nuestro paquete de integración probará el comportamiento de la parte central de nuestra aplicación que no necesariamente necesita tener acceso a Laravel. La suite de integración normalmente será una mezcla de historias de Behat y especificaciones de PhpSpec.

4. Unidad

Nuestras pruebas de unidad se escribirán en PhpSpec y probarán unidades pequeñas aisladas del núcleo de la aplicación. Nuestras entidades, objetos de valor, etc. tendrán todas las especificaciones..

El caso

A lo largo de esta serie, a partir del siguiente artículo, construiremos un sistema para el tiempo de seguimiento. Comenzaremos describiendo el comportamiento desde el exterior escribiendo las características de Behat. El comportamiento interno de nuestra aplicación se describirá utilizando PhpSpec. 

Juntas, estas dos herramientas nos ayudarán a sentirnos cómodos con la calidad de la aplicación que estamos creando. Principalmente escribiremos características y especificaciones en tres niveles: 

  1. Funcional
  2. Integración
  3. Unidad


En nuestra suite funcional, rastrearemos las respuestas HTTP de nuestra aplicación en un modo sin cabeza, lo que significa que no iremos a través del navegador. Esto facilitará la interacción con Laravel y hará que nuestra suite funcional también sea nuestra capa de aceptación.. 

Más adelante, si terminamos teniendo una IU más complicada y es posible que también necesitemos probar algunos JavaScript, podríamos agregar un paquete de aceptación dedicado. Esta serie aún está en progreso, por lo que puede dejar sus sugerencias en la sección de comentarios..

Nuestra configuración

Tenga en cuenta que para este tutorial, asumo que tiene una instalación nueva de Laravel (4.2) en funcionamiento. Preferiblemente, también estás usando Laravel Homestead, que es lo que usé cuando escribí este código.

Antes de comenzar con cualquier trabajo real, asegurémonos de que tenemos Behat y PhpSpec en funcionamiento. Sin embargo, primero, me gusta hacer un poco de limpieza cada vez que comienzo un nuevo proyecto de laravel y elimino las cosas que no necesito:

git rm -r app / tests / phpunit.xml CONTRIBUTING.md

Si elimina estos archivos, asegúrese de actualizar su compositor.json presentar en consecuencia:

"carga automática": "mapa de clase": ["aplicación / comandos", "aplicación / controladores", "aplicación / modelos", "aplicación / base de datos / migraciones", "aplicación / base de datos / semillas"], 

Y por supuesto:

$ compositor dump-autoload

Ahora estamos listos para utilizar las herramientas BDD que necesitamos. Sólo agrega un require-dev sección a tu compositor.json:

"require": "laravel / framework": "4.2. *", "require-dev": "behat / behat": "~ 3.0", "phpspec / phpspec": "~ 2.0", "phpunit / phpunit ":" ~ 4.1 ", 

"¿Por qué estamos tirando en PHPUnit?" usted podría estar pensando? No vamos a escribir buenos casos de prueba de PHPUnit en esta serie, pero las afirmaciones son una herramienta útil junto con Behat. Lo veremos más adelante en este artículo cuando escribamos nuestra primera característica..

Recuerda actualizar tus dependencias después de modificarlas. compositor.json:

$ actualización del compositor --dev

Casi hemos terminado de instalar y configurar cosas. PhpSpec trabaja fuera de la caja:

$ vendor / bin / phpspec ejecutar 0 especificaciones 0 ejemplos 0ms

Pero Behat necesita hacer una carrera rápida con el --en eso Opción para configurar todo:

$ vendor / bin / behat --init + d features - coloque sus archivos * .feature aquí + d features / bootstrap - coloque sus clases de contexto aquí + f features / bootstrap / FeatureContext.php - coloque sus definiciones, transformaciones y enlaces aquí $ proveedor / bin / behat Sin escenarios No hay pasos 0m0.14s (12.18Mb)

El primer comando creó una nueva brillante FeatureContext clase, donde podemos escribir las definiciones de pasos necesarias para nuestras funciones:

Escribiendo nuestra primera característica

Nuestra primera característica será muy simple: simplemente nos aseguraremos de que nuestra nueva instalación de Laravel nos reciba con un mensaje de "Ha llegado". en la página de inicio. Me pongo en un lugar bastante tonto Dado paso también, Dado que estoy conectado, que solo sirve para mostrar lo fácil que es interactuar con Laravel en nuestras funciones..

Técnicamente, categorizaría este tipo de característica como una prueba funcional, ya que interactúa con el marco, pero también sirve como una prueba de aceptación, ya que no veríamos ningún resultado diferente al ejecutar una prueba similar a través de una herramienta de prueba del navegador. Por ahora nos quedaremos con nuestro conjunto de pruebas funcionales..

Sigue adelante y crea un bienvenido. archivar y ponerlo en características / funcional:

# características / funcional / bienvenida. característica Característica: desarrollador acogedor Como desarrollador de Laravel Para comenzar proberamente un nuevo proyecto, necesito que me saluden al llegar Escenario: saludar al desarrollador en la página de inicio Dado que estoy conectado Cuando visito "/" Entonces yo Debería ver "Has llegado". 

Al poner las características funcionales en un funcional Directorio, nos será más fácil administrar nuestras suites más adelante. No queremos características de tipo de integración que no requieran que Laravel tenga que esperar a la suite funcional lenta. 

Me gusta mantener las cosas agradables y limpias, por lo que creo que deberíamos tener un contexto de funciones dedicado para nuestra suite funcional que nos permita acceder a Laravel. Usted puede simplemente seguir adelante y copiar el existente FeatureContext archiva y cambia el nombre de la clase a LaravelFeatureContext. Para que esto funcione, también necesitamos un behat.yml archivo de configuración. 

Cree uno en el directorio raíz de su proyecto y agregue lo siguiente:

predeterminado: suites: funcional: rutas: [% paths.base% / features / function] contexts: [LaravelFeatureContext] 

Creo que el YAML aquí es bastante autoexplicativo. Nuestra suite funcional buscará características en el funcional directorio y ejecutarlos a través de la LaravelFeatureContext.

Si intentamos ejecutar Behat en este punto, nos indicará que implementemos las definiciones de los pasos necesarios. Podemos hacer que Behat agregue los métodos de andamio vacíos a la LaravelFeatureContext con el siguiente comando:

$ vendor / bin / behat --dry-run --append-snippets $ vendor / bin / behat Característica: desarrollador acogedor Como desarrollador de Laravel Para comenzar proberly un nuevo proyecto, necesito que me saluden en el futuro. página de inicio # features / function / welcome.feature: 6 Dado que estoy conectado # LaravelFeatureContext :: iAmLoggedIn () TODO: escribir definición pendiente Cuando visite "/" # LaravelFeatureContext :: iVisit () Luego debería ver "Ha llegado. " # LaravelFeatureContext :: iShouldSee () 1 escenario (1 pendiente) 3 pasos (1 pendiente, 2 omitidos) 0m0.28s (12.53Mb)

Y ahora, como puede ver en la salida, estamos listos para comenzar a implementar el primero de nuestros pasos: Dado que estoy conectado.

El caso de prueba de PHPUnit que se envía con Laravel nos permite hacer cosas como $ this-> be ($ user), que inicia sesión en un usuario determinado. En última instancia, queremos poder interactuar con Laravel como si estuviéramos usando PHPUnit, así que sigamos adelante y escribamos el código de definición del paso "nos gustaría que tuviéramos":

/ ** * @Given Estoy conectado * / public function iAmLoggedIn () $ user = new User; $ this-> be ($ user);  

Por supuesto, esto no funcionará, ya que Behat no tiene idea de cosas específicas de Laravel, pero les mostraré en un segundo lo fácil que es conseguir que Behat y Laravel jueguen bien juntos..

Si echas un vistazo a la fuente de Laravel y encuentras el Illuminate \ Foundation \ Testing \ TestCase clase, que es la clase desde la cual se extiende el caso de prueba predeterminado, verá que a partir de Laravel 4.2, todo se ha movido a un rasgo. los AplicaciónTrait ahora es responsable de arrancar una Solicitud instancia, configurar un cliente HTTP y darnos algunos métodos de ayuda, como ser()

Esto es bastante bueno, principalmente porque significa que simplemente podemos insertarlo en nuestros contextos de Behat sin casi ninguna configuración requerida. También tenemos acceso a la AfirmacionesTrait, pero esto todavía está vinculado a PHPUnit.

Cuando jalamos el rasgo, necesitamos hacer dos cosas. Necesitamos tener un preparar() método, como el de laIlluminate \ Foundation \ Testing \ TestCase clase, y necesitamos un crearAplicación () Método, como el del caso de prueba predeterminado de Laravel. En realidad solo podemos copiar esos dos métodos y usarlos directamente. 

Solo hay una cosa que notar: en PHPUnit, el método preparar() Se llamará automáticamente antes de cada prueba. Para lograr lo mismo en Behat, podemos utilizar el @BeforeScenario anotación.

Agregue lo siguiente a su LaravelFeatureContext:

use Illuminate \ Foundation \ Testing \ ApplicationTrait; / ** * Clase de contexto de Behat. * / class LaravelFeatureContext implementa SnippetAcceptingContext / ** * Responsable de proporcionar una instancia de la aplicación Laravel. * / use ApplicationTrait; / ** * Inicializa el contexto. * * Cada escenario tiene su propio objeto de contexto. * También puede pasar argumentos arbitrarios al constructor de contexto a través de behat.yml. * / public function __construct ()  / ** * @BeforeScenario * / public function setUp () if (! $ this-> app) $ this-> refreshApplication ();  / ** * Crea la aplicación. * * @return \ Symfony \ Component \ HttpKernel \ HttpKernelInterface * / public function createApplication () $ unitTesting = true; $ testEnvironment = 'testing'; el retorno requiere __DIR __. '/… /… /bootstrap/start.php';  

Bastante fácil, y mira lo que obtenemos cuando ejecutamos Behat:

$ vendor / bin / behat Característica: desarrollador acogedor Como desarrollador de Laravel Para comenzar proberamente un nuevo proyecto, necesito que me saluden en el escenario original: saludar al desarrollador en la página de inicio # features / funcional / welcome.feature: 6 Dado que estoy conectado # LaravelFeatureContext :: iAmLoggedIn () Cuando visito "/" # LaravelFeatureContext :: iVisit () TODO: escribe una definición pendiente Luego debería ver "Has llegado". # LaravelFeatureContext :: iShouldSee () 1 escenario (1 pendiente) 3 pasos (1 aprobado, 1 pendiente, 1 omitido) 0m0.73s (17.92Mb)

Un primer paso verde, lo que significa que nuestra configuración está funcionando.!

A continuación, podemos implementar el Cuando yo visite paso. Este es súper fácil, y simplemente podemos usar el llamada()método que el AplicaciónTrait proporciona. Una línea de código nos llevará allí:

/ ** * @ Cuando visito: uri * / public function iVisit ($ uri) $ this-> call ('GET', $ uri);  

El último paso, Entonces debería ver, Toma un poco más y tenemos que tirar en dos dependencias. Necesitaremos PHPUnit para la aserción y necesitaremos el Symfony DomCrawler para buscar "Has llegado". texto.

Podemos implementarlo así:

use PHPUnit_Framework_Assert como PHPUnit; use Symfony \ Component \ DomCrawler \ Crawler;… / ** * @ Entonces debería ver: text * / public function iShouldSee ($ text) $ crawler = new Crawler ($ this-> client-> getResponse () -> getContent ()); PHPUnit :: assertCount (1, $ crawler-> filterXpath ("// text () [. = '$ Text']"));  

Este es prácticamente el mismo código que escribirías si estuvieras usando PHPUnit. los filterXpath () La parte es un poco confusa y no nos preocuparemos por eso ahora, ya que está un poco fuera del alcance de este artículo. Solo confía en mí que funciona.

Correr Behat una última vez es una buena noticia:

$ vendor / bin / behat Característica: desarrollador acogedor Como desarrollador de Laravel Para comenzar proberamente un nuevo proyecto, necesito que me saluden en el escenario original: saludar al desarrollador en la página de inicio # features / funcional / welcome.feature: 6 Dado que estoy conectado # LaravelFeatureContext :: iAmLoggedIn () Cuando visite "/" # LaravelFeatureContext :: iVisit () Luego debería ver "Ha llegado." # LaravelFeatureContext :: iShouldSee () 1 escenario (1 aprobado) 3 pasos (3 aprobados) 0m0.82s (19.46Mb)

La función está funcionando como se esperaba y el desarrollador es recibido al llegar.

Conclusión

El completo LaravelFeatureContext Ahora debería verse similar a esto:

aplicación) $ this-> refreshApplication ();  / ** * Crea la aplicación. * * @return \ Symfony \ Component \ HttpKernel \ HttpKernelInterface * / public function createApplication () $ unitTesting = true; $ testEnvironment = 'testing'; el retorno requiere __DIR __. '/… /… /bootstrap/start.php';  / ** * @ Entregado estoy conectado * / public function iAmLoggedIn () $ user = new User; $ this-> be ($ user);  / ** * @ Cuando visito: uri * / public function iVisit ($ uri) $ this-> call ('GET', $ uri);  / ** * @ Entonces debería ver: text * / public function iShouldSee ($ text) $ crawler = new Crawler ($ this-> client-> getResponse () -> getContent ()); PHPUnit :: assertCount (1, $ crawler-> filterXpath ("// text () [. = '$ Text']"));  

Ahora tenemos una base muy buena sobre la cual construir a medida que continuamos desarrollando nuestra nueva aplicación Laravel utilizando BDD. Espero haberte demostrado lo fácil que es conseguir que Laravel y Behat jueguen bien juntos. 

Hemos tocado muchos temas diferentes en este primer artículo. No se preocupe, analizaremos todo a medida que la serie continúe. Si tiene alguna pregunta o sugerencia, por favor deje un comentario..