En una de las materias que doy en la facultad (Programación Web II – TUPAR), estamos continuando un proyecto para los Bomberos de Trenque Lauquen.
Es un proyecto que comenzaron unos alumnos como trabajo de fin de carrera. Es una aplicación web para administrar el cuartel: materiales, vehículos, bomberos, asistencias, promociones de personal, etc. Si bien aún esta en Alpha, es un buen proyecto para aplicar muchísimos de los conceptos de Programación Web.
Este año decidimos enseñar Docker y Laravel, y uno de los conceptos claves que queremos que los alumnos aprendan es la calidad de código, hacer unit test e integration tests, probar un poco de TDD y tener la experiencia de usar un ambiente de Integración Continua.
La idea de este post es poder poner en forma de tutorial como configurar Travis-CI, para hacer el build de una aplicación escrita en Laravel, con tests de unidad y tests de integración.
Laravel y Testing
Laravel es un framework de PHP, según su página web: The PHP Framework For Web Artisans.
Tiene muchas features muy interesantes, como las migrations, el comando artisan, los templates de Blade, Eloquent, y más.
Uno de los puntos fuertes es lo bien integrado que está con la creación de test alrededor de la solución.
Obviamente que para los tests de unidad, usa PHPUnit, que ya está más que probado y es el standard de la industria. Pero para los tests de integración, usa Dusk, que es una herramienta que automatiza los browser tests y esta integrada con Artisan para correr.
Configurando de Travis
Lo primero que vamos a hacer es crear el archivo travis.yml, este es el archivo que le dice a Travis como tiene que crear el container para poder ejecutar los tests de nuestra aplicación.
https://gist.github.com/ignaciojonas/74ef17246102674eec0ff09d58c67883#file-travis-yml
Hasta llegar a este archivo terminado tuve unas cuantas luchas. En primer lugar seguí la explicación de la documentación oficial, sin ninguna suerte. Después de buscar mucho en Google, encontré a un post en Japones, en el cual @sutara_lumpur, explicaba como el había hecho para configurarlo y tenia un repo en Github con la solución andando.
Obviamente le agradecí como corresponde:
Vamos a explicar un poco que dice este archivo, las partes que a mi me generaron más dudas, hay algunas partes que se auto-explican.
- sudo: required : Para poder ejecutar Chrome necesitamos permisos de root en el container.
- dist: trusty : Como necesitamos ejecutar Chrome, entonces nuestro container tiene que ser un Linux, en este caso Ubuntu Trusty.
- services : Vamos a necesitar una base de datos para probar nuestra aplicación, en este caso Postgres.
- addons: Necesitamos que nuestro container tenga Chrome instalado, para correr los test de integración.
- install: Ejecutamos composer install para que instale todas las dependencias.
- before script:
- Creamos la base de datos, el nombre tiene que coincidir con lo que luego pongamos en el .env.travis.
- Creamos el archivo .env, copiando el archivo .env.travis con toda la configuración.
- Generamos la key para que nuestra aplicación Laravel funcione.
- Migramos la base de datos y además le cargamos los datos. En este punto podemos obviar el –seed, si es que vamos a regenerar la base por cada test que ejecute.
- script
- Ejecutamos Chrome y lo ponemos a escuchar en un puerto, en nuestro caso 9222, este puerto tiene que coincidir con el puerto que usemos en DuskTestCase.php
- Levantamos el server para poder acceder a nuestra aplicación usando artisan, redirigir el output a /dev/null es opcional. De esta forma nos queda mas limpio el log de Travis.
- Ejecutamos los tests de integración.
- Ejecutamos los tests de unidad, y generamos el archivo de coverage
- after_success
- Creamos el reporte de coverage.
Ya tenemos nuestro archivo de configuración de Travis. Ahora creemos nuestro archivo .env.travis.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
APP_ENV=testing | |
APP_DEBUG=true | |
APP_KEY= | |
APP_URL=http://localhost:8000 | |
DB_CONNECTION=pgsql | |
DB_HOST=localhost | |
DB_PORT=5432 | |
DB_DATABASE=bomberos_test | |
DB_USERNAME=postgres | |
DB_PASSWORD= | |
CACHE_DRIVER=array | |
SESSION_DRIVER=file | |
QUEUE_DRIVER=sync | |
TRAVIS=true | |
CHROME_HOST=http://localhost:9515 |
Este archivo, en nuestro caso, es casi una copia de el .env que tenemos en nuestra maquina local. La diferencia son:
- DB_DATABASE: Ahora apunta a la base de datos que creamos en Travis.
- DB_USER: Es el usuario de la base de datos del container de Travis.
- DB_PASSWORD: Es vacío, porque el default password del usuario postgres en Travis es vacío.
- TRAVIS: Es para indicar que estamos corriendo en Travis, esto me va a servir para hacer algunos cambios en el archivo DuskTestCase.php.
- CHROME_HOST: Es la URL donde escucha Chrome.
Por último, hacemos un pequeño cambio en el archivo DuskTestCase.php
Este cambio nos ayuda a poder ejecutar los tests tanto en el ambiente de desarrollo como en Travis.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
... | |
protected function driver() | |
{ | |
$options_array = env('TRAVIS', false) ? ['–disable-gpu','–headless','–window-size=1100,600'] : []; | |
$options = (new ChromeOptions)->addArguments($options_array); | |
return RemoteWebDriver::create( | |
env('CHROME_HOST', 'http://selenium:4444/wd/hub'), DesiredCapabilities::chrome()->setCapability( | |
ChromeOptions::CAPABILITY, $options | |
) | |
); | |
} | |
?> |
En nuestro caso tenemos un ambiente de desarrollo en Docker, en el cual tenemos los siguientes containers:
- app: Corremos PHP.
- web: Corremos el Server (nginx).
- database: Corremos Postgres.
- adminer: Corremos adminer, para poder administrar la Base de Datos.
- selenium: Corremos Chrome y dentro de este container corremos los test de integración.
Para correr los Tests de Integración, tenemos que usar la URL http://selenium:4444/wd/hub y si pasamos las options de headless, disable-gpu, etc. se hace muy lento, al punto de fallar por timeout.
Una vez que subimos estos cambios y configuramos Travis para que integre nuestro repositorios, la aplicación buildea.
Y tenemos el reporte de coverage, de lo que cubren los test de unidad. Como vemos es de un 3%, muy poco, pero ahora que lo podemos medir, lo podemos mejorar.
Espero que les sirva, nos estamos leyendo.