Cobertura de código de prueba del mito a la realidad

Hubo un momento en que a los programadores se les pagaba por la cantidad de líneas de código que escribían. Fueron tratados como máquinas fuente de código fuente que trabajan en cubículos y, a cambio, consideraron la programación como un trabajo que realizan ocho horas al día y luego se olvidan de ello, durante el resto del día..

Pero los tiempos han cambiado. La mayoría de los lugares de trabajo en los cubículos desaparecieron y los programadores comenzaron a amar su oficio. Con la llegada de las técnicas ágiles y el movimiento de la artesanía del software, surgieron muchas herramientas nuevas para ayudar al programador y al proceso. TDD se está convirtiendo lentamente en la forma de facto de escribir código y los secretos de SCRUM o Kanban se revelaron incluso a los programadores en los rincones más oscuros del mundo de cubículos..

Las pruebas automatizadas y el desarrollo dirigido por pruebas (TDD) son algunas de las técnicas esenciales que Agile nos brinda a los programadores. Y una herramienta que viene con esas metodologías se utiliza para producir cobertura de código de prueba, que es el tema de este artículo..

Definición

"En informática, la cobertura de código es una medida utilizada para describir el grado en que un conjunto de pruebas en particular prueba el código fuente de un programa". ~ Wikipedia

La definición anterior, tomada de Wikipedia, es una de las formas más simples de describir lo que significa la cobertura de código. Básicamente, en su proyecto tiene un montón de código de producción, así como un montón de código de prueba. El código de prueba ejerce el código de producción y la cobertura de la prueba le indica qué parte de su código de producción fue ejercido por las pruebas.

La información se puede presentar de varias maneras, desde porcentajes simples hasta gráficos agradables o incluso resaltados en tiempo real en su IDE favorito.

Vamos a comprobarlo en acción

Usaremos PHP como el lenguaje para ejemplificar nuestro código. Además, necesitaremos PHPUnit y XDebug para probar nuestro código y recopilar datos de cobertura.

El código fuente

Aquí está el código fuente que usaremos. También puedes encontrarlo en el archivo adjunto..

clase WordWrap función pública de ajuste ($ string = ", $ cols) $ cadena = recortar ($ cadena); if (strlen ($ cadena)> $ cols) $ lastSpaceIndex = strrpos (substr ($ cadena, 0, $ cols), "); if ($ lastSpaceIndex! == false && substr ($ string, $ cols, 1)! = ") return substr ($ string, 0, $ lastSpaceIndex)." \ n ". $ this-> wrap (substr ($ string, $ lastSpaceIndex), $ cols); else return substr ($ string, 0, $ cols). "\ n". $ this-> wrap (substr ($ string, $ cols), $ cols);  devuelve $ cadena;

El código anterior contiene una función simple que ajusta el texto a un número específico de caracteres, por línea.

El código de prueba

Escribimos este código usando Test Driven Development (TDD) y tenemos una cobertura de código del 100% para él. Esto significa que al ejecutar nuestra prueba, ejercitamos todas y cada una de las líneas del código fuente..

require_once __DIR__. '/… /WordWrap.php'; la clase WordWrapTest extiende PHPUnit_Framework_TestCase function testItCanWrap () $ w = new WordWrap (); $ this-> assertEquals (", $ w-> wrap (null, 0)); $ this-> assertEquals (", $ w-> wrap (", 0)); $ this-> assertEquals ('a', $ w-> wrap ('a', 1)); $ this-> assertEquals ("a \ nb", $ w-> wrap ('a b', 1)); $ this-> assertEquals ("ab \ nc ", $ w-> wrap ('ab c', 3)); $ this-> assertEquals (" a \ nbc \ nd ", $ w-> wrap ('a bc d', 3));

Ejecutar las pruebas en CLI con cobertura de solo texto

Una forma de obtener datos de cobertura es ejecutar nuestras pruebas en la CLI (interfaz de línea de comandos) y analizar el resultado. Para este ejemplo, asumiremos un sistema operativo similar a UNIX (Linux, MacOS, FreeBSD, etc.). Los usuarios de Windows deberán adaptar ligeramente las rutas y los nombres de los ejecutables, pero deberían ser bastante similares..

Abramos una consola y cambiemos directorios a tu prueba carpeta. Entonces corre phpunit Con una opción para generar datos de cobertura como texto plano..

phpunit --coverage-text =. / coverage.txt ./WordWrapTest.php

Esto debería funcionar de inmediato en la mayoría de los sistemas si XDebug está instalado, sin embargo, en algunos casos, es posible que encuentre un error relacionado con las zonas horarias.

Advertencia de PHP: fecha (): no es seguro confiar en la configuración de zona horaria del sistema. Usted es * requerido * para usar la configuración date.timezone o la función date_default_timezone_set (). En caso de que haya usado alguno de esos métodos y aún reciba esta advertencia, lo más probable es que haya escrito incorrectamente el identificador de zona horaria. Hemos seleccionado la zona horaria 'UTC' por ahora, pero configure fecha.zona horaria para seleccionar su zona horaria. en phar: ///usr/share/php/phpunit/phpunit.phar/ PHP_CodeCoverage-1.2.10 / PHP / CodeCoverage / Report / Text.php en la línea 124 

Esto se puede solucionar fácilmente especificando la configuración sugerida en su php.ini expediente. Puede encontrar la manera de especificar su zona horaria en esta lista. Soy de Rumania, así que usaré la siguiente configuración:

date.timezone = Europa / Bucarest

Ahora, si corres el phpunit comando de nuevo, no debería ver mensajes de error. En su lugar, se mostrarán los resultados de la prueba..

PHPUnit 3.7.20 por Sebastian Bergmann ... Tiempo: 0 segundos, Memoria: 5.00Mb OK (2 pruebas, 7 aserciones) 

Y los datos de cobertura estarán en el archivo de texto especificado..

$ cat ./coverage.txt Informe de cobertura de código 2014-03-02 13:48:11 Resumen: Clases: 100.00% (1/1) Métodos: 100.00% (1/1) Líneas: 2.68% (14/522) WordWrap Métodos: 100.00% (1/1) Líneas: 100.00% (7/7) 

Analicemos esto un poco.

  • Las clases: se refiere a cuántas clases se evaluaron y cuántas de ellas se cubrieron. Ajuste de línea es nuestra única clase.
  • Métodos: igual que con las clases. Solo tenemos nuestro envolver() método, nada más.
  • Líneas: igual que el anterior, pero para líneas de código. Aquí tenemos muchas líneas porque el resumen contiene todas las líneas de PHPUnit..
  • Luego tenemos una sección para cada clase. En nuestro caso, eso es solo. Ajuste de línea. Cada sección tiene sus propios métodos y detalles de línea..

Con base en estas observaciones, podemos concluir que nuestro código está cubierto al 100% por las pruebas. Exactamente como esperábamos antes de analizar los datos de cobertura..

Generando salida de cobertura HTML

Con solo cambiar un parámetro simple para PHPUnit, podemos generar un buen resultado HTML.

$ mkdir ./coverage $ phpunit --coverage-html ./coverage ./WordWrapTest.php 

Si revisas tu ./cobertura directorio, encontrará una gran cantidad de archivos allí. No pegaré la lista aquí porque es bastante extensa. En su lugar, te mostraré cómo se ve en un navegador web..

Este es el equivalente de la sección de resumen de la versión de texto anterior. Podemos acercarnos siguiendo los enlaces propuestos y ver más detalles..

Cobertura dentro de nuestro IDE

Los ejemplos anteriores fueron interesantes y son bastante útiles., Si su código se basa en algún servidor remoto al que solo tiene acceso SHH o web. Pero, ¿no sería bueno tener toda esta información en vivo en su IDE??

Si utiliza PHPStorm, todo está a la distancia de un solo clic. Seleccione ejecutar sus pruebas con cobertura y toda la información simplemente aparecerá, mágicamente.

La información de cobertura estará presente en su IDE, de varias maneras y en varios lugares:

  1. El porcentaje de cobertura de la prueba se mostrará cerca de cada directorio y archivo.
  2. En el editor, mientras edita el código, a la izquierda de los números de línea, un rectángulo verde o rojo marcará cada línea. El verde representa líneas probadas, el rojo representa las no probadas. Las líneas sin código real (líneas vacías, solo llaves o paréntesis, declaraciones de clase o método) no tendrán ninguna marca.
  3. En el lado derecho, habrá navegadores de archivos donde podrá buscar y ordenar rápidamente los archivos por cobertura..
  4. En la salida de la prueba, verá una línea de texto que le informa que se generó la cobertura del código.

Los mitos sobre la cobertura de código

Con una herramienta tan poderosa en las manos del desarrollador y bajo la nariz de la gerencia, era inevitable que surgieran algunos mitos. Después de que los programadores se negaron a pagar por la cantidad de líneas de código que escriben, o los gerentes se dieron cuenta de lo fácil que es jugar con el sistema, algunos de ellos comenzaron a pagar a los programadores por el porcentaje de cobertura de código. Una mayor cobertura de código significa que el programador fue más cuidadoso, ¿verdad? Es un mito La cobertura del código no es una medida de lo bien que se escribe el código.

A veces los programadores tienden a pensar que el código con una cobertura del 100% no tiene errores. Otro mito. La cobertura del código simplemente le indica que ha probado cada línea de código. Es una medida del número de líneas ejercitadas. No es una medida del número de líneas correctamente implementadas. Por ejemplo, la mitad de los algoritmos escritos con solo la mitad de las pruebas definidas todavía tendrán una cobertura del 100%. Esto no significa que el algoritmo esté terminado o que funcione correctamente.

Finalmente, jugar el sistema es muy fácil. Por supuesto, si usa TDD, naturalmente tiene un alto valor de cobertura. En proyectos completos, el 100% es imposible. Pero en pequeños módulos o clases, obtener una cobertura del 100% es muy fácil. Tome por ejemplo nuestro código fuente e imagine que no tiene ninguna prueba. ¿Cuál sería la prueba más sencilla para ejercitar todo el código??

función testItCanWrap () $ w = new WordWrap (); $ this-> assertEquals ("a b \ nc", $ w-> wrap ('a b c', 3)); $ this-> assertEquals ("a \ nbc \ nd", $ w-> wrap ('a bc d', 3)); 

Eso es. Dos aseveraciones y cobertura total. Esto no es lo que queremos. Esta prueba está tan lejos de ser descriptiva y completa, que es ridícula.

La realidad sobre la cobertura de código

La cobertura del código es un indicador de estado, no una unidad para medir el rendimiento o la corrección.

La cobertura del código es para programadores, no para gerentes. Es una forma de detectar problemas en nuestro código. Una forma de encontrar clases antiguas, no probadas. Una forma de encontrar caminos que los exámenes no pueden llevar a problemas..

En proyectos reales, la cobertura del código siempre será inferior al 100%. No es posible lograr una cobertura perfecta, o si lo es, rara vez es una obligación. Sin embargo, para tener un 98% de cobertura debes apuntar al 100%. Tener cualquier otra cosa como tu objetivo no tiene sentido.

Aquí está el código de cobertura en la aplicación de configuración StorageOS de Syneto..

El total es solo alrededor del 35%, pero los resultados necesitan interpretación. La mayoría de los módulos están en verde, con más del 70% de cobertura. Sin embargo hay una sola carpeta., Vmware, que baja el promedio. Es un módulo con muchas clases que solo contienen definiciones para la API de comunicación. No hay razón para probar esas clases. Fueron generados automáticamente por código de confianza. Los programadores sabrán esto y sabrán cómo interpretar los resultados. Un gerente puede insistir en probarlo porque es una barra roja y parece sospechoso para alguien que no conoce los detalles internos del proyecto. ¿Tendría algún sentido probarlo? ¡De ningún modo! Sería una prueba inútil, que tomaría preciosos decenas de segundos de tiempo de construcción sin ninguna ventaja..

Pensamientos finales

Así que aquí es donde estamos con la cobertura de código: es una gran herramienta para los programadores, una fuente de información para resaltar posibles problemas, una realidad mal entendida para la mayoría de los gerentes y otra herramienta para forzar y medir las actividades de los programadores. Al igual que con cualquier otra herramienta, es una que se puede usar correctamente y se puede utilizar mal fácilmente..