En este tutorial nos centraremos en explicar cómo obtener informes de cobertura para conocer el grado en que nuestras aplicaciones del front han sido probadas.
Índice de contenidos
- 1. Introducción
- 2. Entorno
- 3. Creación del proyecto con NPM
- 4. Creando un ejemplo con código JavaScript
- 5. Ejecutando las pruebas
- 6. Conclusiones
- 7. Referencias
1. Introducción
Cuando nos proponemos realizar aplicaciones de calidad es importante establecer métricas sobre las que podamos evaluarlas. En tal sentido, una métrica comúnmente utilizada para evaluar objetivamente la calidad de nuestras aplicaciones es comprobar lo exhaustivas que han sido las pruebas sobre su código fuente.
Por lo tanto, la motivación principal en este tutorial es centrarnos en explicar cómo obtener informes de cobertura para conocer el grado en que nuestras aplicaciones del front han sido probadas.
2. Entorno
El tutorial está escrito usando el siguiente entorno:
- Hardware: Portátil MacBook Pro Retina 15′ (2.5 Ghz Intel Core I7, 16GB DDR3).
- Sistema Operativo: Mac OS El Capitán 10.11.4
- Node 5.7.1
- npm 3.8.8
- Jasmine 2.4.1
- Karma v0.13.22
- Phantom JS 2.1.7
3. Creación del proyecto con NPM
El primer paso que ejecutaremos será crear un proyecto JavaScript con la utilidad npm init para guiarnos en la creación del fichero package.json:
MacBook-Pro-de-jmangialomini:TutorialKarma jmangialomini$ npm init This utility will walk you through creating a package.json file. It only covers the most common items, and tries to guess sensible defaults. See `npm help json` for definitive documentation on these fields and exactly what they do. Use `npm install <pkg> --save` afterwards to install a package and save it as a dependency in the package.json file. Press ^C at any time to quit. name: (TutorialKarma) tutorialkarma version: (1.0.0) description: Tutorial Karma Coverage entry point: (index.js) test command: karma start karma.conf.js git repository: keywords: author: Jose Mangialomini license: (ISC) About to write to /Users/jmangialomini/workspace/TutorialKarma/package.json: { "name": "tutorialkarma", "version": "1.0.0", "description": "Tutorial Karma Coverage", "main": "index.js", "scripts": { "test": "karma start karma.conf.js" }, "author": "Jose Mangialomini", "license": "ISC" } Is this ok? (yes) yes
Aunque se configuraron varios parámetros básicos, uno importante que se debe destacar es el comando para los test que más adelante utilizaremos para ejecutar las pruebas de cobertura con karma.
3.1.Configurando las dependencias
Una vez configurada la estructura básica del proyecto, el siguiente paso es configurar las dependencias necesarias.
Las primeras que se deben incorporar son las de Karma y Karma-Coverage, con ellas se podrán conectar un conjunto específico de navegadores web, ejecutar pruebas y luego recoger el informe de la cobertura:
npm install karma karma-coverage --save-dev
Luego de instaladas las dependencias de Karma será necesario configurar las de Jasmine para contar con un framework de pruebas para nuestro código JavaScript:
npm install jasmine karma-jasmine --save-dev
Finalmente y para automatizar la interacción web se instalarán las dependencias de PhantomJS como navegador sin interfaz gráfica:
npm install phantomjs-prebuilt karma-phantomjs-launcher --save-dev
Una ventaja muy útil de instalar las dependencias con npm es que se actualizan automáticamente en el fichero package.json. El de nuestro ejemplo debería quedar de la siguiente manera:
{ "name": "tutorialkarma", "version": "1.0.0", "description": "Tutorial Karma Coverage", "main": "index.js", "scripts": { "test": "karma start karma.conf.js" }, "author": "Jose Mangialomini", "license": "ISC", "devDependencies": { "jasmine": "^2.4.1", "karma": "^0.13.22", "karma-chrome-launcher": "^1.0.1", "karma-coverage": "^1.0.0", "karma-jasmine": "^1.0.2", "karma-phantomjs-launcher": "^1.0.0", "phantomjs-prebuilt": "^2.1.7" } }
3.2. Configurando Karma
El siguiente paso para obtener nuestros informes de cobertura es hacer que Karma funcione, para ello debemos configurar el fichero karma.conf.js con la utilidad de karma init:
MacBook-Pro-de-jmangialomini:TutorialKarma jmangialomini$ karma init Which testing framework do you want to use ? Press tab to list possible options. Enter to move to the next question. > jasmine Do you want to use Require.js ? This will add Require.js plugin. Press tab to list possible options. Enter to move to the next question. > no Do you want to capture any browsers automatically ? Press tab to list possible options. Enter empty string to move to the next question. > PhantomJS > What is the location of your source and test files ? You can use glob patterns, eg. "js/*.js" or "test/**/*Spec.js". Enter empty string to move to the next question. > Should any of the files included by the previous patterns be excluded ? You can use glob patterns, eg. "**/*.swp". Enter empty string to move to the next question. > Do you want Karma to watch all the files and run the tests on change ? Press tab to list possible options. > yes Config file generated at "/Users/jmangialomini/workspace/TutorialKarma/karma.conf.js". MacBook-Pro-de-jmangialomini:TutorialKarma jmangialomini$
Para que Karma ejecute el análisis de la cobertura de las pruebas modificaremos manualmente el fichero karma.conf.js para indicarle que debe reportar la cobertura utilizando Phantom JS como navegador para simular la interacción web.
// Karma configuration // Generated on Wed May 04 2016 15:42:31 GMT+0200 (CEST) module.exports = function(config) { config.set({ // base path that will be used to resolve all patterns (eg. files, exclude) basePath: '', // frameworks to use // available frameworks: https://npmjs.org/browse/keyword/karma-adapter frameworks: ['jasmine'], // list of files / patterns to load in the browser files: [ 'app/*.js', 'tests/*.test.js' ], // list of files to exclude exclude: [ ], // preprocess matching files before serving them to the browser // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor preprocessors: { 'app/*.js': ['coverage'] }, // test results reporter to use // possible values: 'dots', 'progress' // available reporters: https://npmjs.org/browse/keyword/karma-reporter reporters: ['progress', 'coverage'], // web server port port: 9876, // enable / disable colors in the output (reporters and logs) colors: true, // level of logging // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN // || config.LOG_INFO || config.LOG_DEBUG logLevel: config.LOG_INFO, // enable / disable watching file and executing tests whenever any file changes autoWatch: true, // start these browsers // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher browsers: ['PhantomJS'], // Continuous Integration mode // if true, Karma captures browsers, runs the tests and exits singleRun: false, // Concurrency level // how many browser should be started simultaneous concurrency: Infinity }) }
Nótese que en este fichero se modificaron los valores de los parámetros preprocessors y reporters para incorporar el valor coverage.
4.Creando un ejemplo con código JavaScript
Ya casi para terminar y para poder validar los reportes de cobertura generados por Karma, vamos a crear un pequeño ejemplo con un fichero javascript y su prueba.
Primero que todo y promoviendo el uso de TDD vamos a crear dentro de la carpeta specs/ un fichero hello.test.js donde con Jasmine programaremos el resultado esperado para una función Hello Word tal cual se muestra a continuación:
describe("Hello world", function() { it("says hello", function() { expect(helloWorld()).toEqual("Hello world!"); }); });
Por último, implementamos el fichero hello.js dentro la carpeta app/
function helloWorld() { return "Hello world!"; }
5. Ejecutando las pruebas
Finalmente para conocer la cobertura de las pruebas de nuestro ejemplo utilizaremos el comando npm test:
MacBook-Pro-de-jmangialomini:TutorialKarma jmangialomini$ npm test > tutorialkarma@1.0.0 test /Users/jmangialomini/workspace/TutorialKarma > karma start karma.conf.js 14 05 2016 14:19:50.067:WARN [karma]: No captured browser, open http://localhost:9876/ 14 05 2016 14:19:50.076:INFO [karma]: Karma v0.13.22 server started at http://localhost:9876/ 14 05 2016 14:19:50.080:INFO [launcher]: Starting browser PhantomJS 14 05 2016 14:19:50.729:INFO [PhantomJS 2.1.1 (Mac OS X 0.0.0)]: Connected on socket /#08IjLdHbr2riwVYoAAAA with id 60926882 PhantomJS 2.1.1 (Mac OS X 0.0.0): Executed 1 of 1 SUCCESS (0.003 secs / 0.002 secs)
De esta ejecución se genera un fichero index.html dentro de la carpeta /coverage/PhantomJS 2.1.1 (Mac OS X 0.0.0), tal y como se refleja a continuación:
6. Conclusiones
Siempre que nos interese desarrollar aplicaciones de calidad, es importante que podamos demostrarlo y una manera de hacerlo es utilizar la cobertura como métrica que lo refleje. La cobertura de nuestras pruebas nos permitirá identificar debilidades y determinar si puede ser necesario añadir pruebas adicionales para asegurar la calidad del código. Por tanto, es importante tener en cuenta que la cobertura representa la calidad de sus pruebas en lugar de la calidad del código.
Buenos días,
me llamo Dailos Díaz y antes que nada, muchas gracias por la aportación. Ha sido muy clara y directa al objetivo.
Una vez dicho esto, me gustaría saber si me podría resolver una duda que tengo acerca de la cobertura de tests.
Actualmente me encuentro desarrollando una aplicación en Ionic y le estoy aplicando TDD a los servicios y componentes de la misma.
Mi pregunta es, de manera genérica ¿a partir de qué porcentaje de cobertura se considera que un desarrollo está adecuadamente testeado?
La pregunta se origina en base a múltiples charlas a las que he asistido de TDD donde los ponentes indicaban que NO ES NECESARIO alcanzar un 100% de cobertura.
A esto debo añadirle mi experiencia personal donde, por ejemplo, un determinado método se invoca para obtener de una API un conjunto de datos y procesarlos posteriormente para que estén disponibles para el usuario en un determinado formato.
Dicho método realmente está invocando a otros dos métodos: el primero realiza la llamada a la API y con los resultados obtenidos, mediante una «promise», se invoca a un segundo método que procesa los datos recibidos y los prepara para que sean utilizados por la aplicación y por tanto, por el usuario.
Ahora bien, si ya he realizado los tests tanto para el método que realiza la llamada a la API como para el método que procesa los datos que se obtienen de dicha API, ¿es necesario realizar el test para el método que los engloba a ambos?
Gracias de antemano y saludos.
Buenos días Dailos,
Me alegra que el tutorial te aportara. Respondiendo a tus inquietudes intentare abordarlas según las planteas:
1. El objetivo de la cobertura es dar garantías de la calidad del código y el porcentaje que establezcamos vendrá determinado por lo estrictos que seamos con nuestros desarrollos. Habitualmente y basándome en la experiencia, establecer una cobertura del 60% es una buena práctica pero exigir el 85% es la mejor de ellas. Llegar al 100% suele ser ambicioso y quizás por ello hayas escuchado que no es necesario, yo diría que no es imposible pero si ambicioso.
2. En cuanto al: ¿Cómo debo orientar mis pruebas? te diría que la cobertura valida si existe un método que evalúe nuestros desarrollos. En tal sentido, es importante que distingamos si las pruebas son unitarias y cumplen el principio FIRST (fast, isolate, repeatable, self-validating, timely) o si queremos evaluar el comportamiento conjunto (que es lo que llamamos pruebas de integración). Si me preguntaras cuales deberías hacer te diría que debes hacer ambas porque tienen objetivos distintos y ambos son importantes. Principalmente y para enmarcar esto en el contexto de la evaluación de la cobertura, está se mide generalmente con el alcance de las pruebas unitarias ya que abstrae la prueba al funcionamiento esperado por el sujeto objetivo, certificando una cobertura más real.
Espero haberte ayudado.