para - Alcanzar el 100% de cobertura de código con PHPUnit
phpunit tutorial español (4)
He estado en el proceso de crear un banco de pruebas para un proyecto, y aunque me doy cuenta de que obtener el 100% de cobertura no es la métrica que uno debe esforzarse, hay un poco extraño en el informe de cobertura del código al que me gustaría aclaración.
Ver captura de pantalla:
Como la última línea del método que se está probando es una return
, la línea final (que es solo un corchete de cierre) aparece como nunca se está ejecutando, y como consecuencia, todo el método se marca como no ejecutado en la vista general. (O eso, o no estoy leyendo el informe correctamente).
El método completo:
static public function &getDomain($domain = null) {
$domain = $domain ?: self::domain();
if (! array_key_exists($domain, self::$domains)) {
self::$domains[$domain] = new Config();
}
return self::$domains[$domain];
}
¿Hay alguna razón para esto o es un problema técnico?
(Sí, leí cómo obtener cobertura de código 100% con PHPUnit , caso diferente aunque similar).
Editar:
Mientras avanzaba a través del informe, noté que lo mismo es cierto para una declaración de switch
en otra parte del código. Entonces, este comportamiento es al menos en cierta medida constante, pero desconcertante para mí.
Edit2:
Me estoy ejecutando: PHPUnit 3.6.7, PHP 5.4.0RC5, XDebug 2.2.0-dev en un OS X
Con respecto a su problema de cobertura del código de declaración de cambio, simplemente agregue un caso "predeterminado" que no hace nada y obtendrá cobertura completa.
En primer lugar: la cobertura del código del 100% es una gran medida para esforzarse . Simplemente no siempre se puede lograr con una buena cantidad de esfuerzo y no siempre es importante hacerlo :)
El problema viene de xDebug diciendo a PHPUnit que esta línea es ejecutable pero no está cubierta.
Para casos simples, xDebug puede decir que la línea NO es accesible, por lo que obtienes cobertura de código del 100% allí.
Vea el ejemplo simple a continuación.
2da actualización
El problema ahora está arreglado xDebug bugtracker
por lo que la construcción de una nueva versión de xDebug resolverá esos problemas :)
Actualización (consulte a continuación los problemas con php 5.3.x)
Como está ejecutando PHP 5.4 y la versión DEV de xDebug, los instalé y probé. Me encuentro con los mismos problemas que tú con el mismo resultado que has comentado.
No estoy 100% seguro de si el problema proviene de php-code-coverage
(el módulo phpunit) para xDebug. También podría ser un problema con xDebug dev.
He archivado un error con php-code-coverage
y averiguaremos de dónde viene el problema.
Para problemas de PHP 5.3.x:
Para casos más complejos, esto CAN puede fallar.
Para el código que mostró todo lo que puedo decir es que "Funciona para mí" ( muestra compleja a continuación ).
Tal vez actualice las versiones de xDebug y PHPUnit y vuelva a intentarlo.
Lo he visto fallar con las versiones actuales, pero depende de cómo se vea la clase a veces.
?:
Quitar ?:
operadores y otras cosas de varias frases de línea única también pueden ayudar.
Hay una refactorización en curso en xDebug para evitar más de esos casos, hasta donde yo sé. xDebug una vez quiere ser capaz de proporcionar "cobertura de declaración" y eso debería solucionar muchos de esos casos. Por ahora no hay mucho que uno pueda hacer aquí
Si bien //@codeCoverageIgnoreStart
y //@codeCoverageIgnoreEnd
obtendrán esta línea "cubierta", se ve muy fea y, por lo general, está haciendo más mal que bien.
Para otro caso donde esto sucede, vea la pregunta y las respuestas de:
what-to-do-when-project-coding-standards-conflicts-with-unit-test-code-coverage
Ejemplo simple:
<?php
class FooTest extends PHPUnit_Framework_TestCase {
public function testBar() {
$x = new Foo();
$this->assertSame(1, $x->bar());
}
}
<?php
class Foo {
public function bar() {
return 1;
}
}
produce:
phpunit --coverage-text mep.php
PHPUnit 3.6.7 by Sebastian Bergmann.
.
Time: 0 seconds, Memory: 3.50Mb
OK (1 test, 1 assertion)
Generating textual code coverage report, this may take a moment.
Code Coverage Report
2012-01-10 15:54:56
Summary:
Classes: 100.00% (2/2)
Methods: 100.00% (1/1)
Lines: 100.00% (1/1)
Foo
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 1/ 1)
Ejemplo complejo:
<?php
require __DIR__ . ''/foo.php'';
class FooTest extends PHPUnit_Framework_TestCase {
public function testBar() {
$this->assertSame(''b'', Foo::getDomain(''a''));
$this->assertInstanceOf(''Config'', Foo::getDomain(''foo''));
}
}
<?php
class Foo {
static $domains = array(''a'' => ''b'');
static public function &getDomain($domain = null) {
$domain = $domain ?: self::domain();
if (! array_key_exists($domain, self::$domains)) {
self::$domains[$domain] = new Config();
}
return self::$domains[$domain];
}
}
class Config {}
produce:
PHPUnit 3.6.7 by Sebastian Bergmann.
.
Time: 0 seconds, Memory: 3.50Mb
OK (1 test, 2 assertions)
Generating textual code coverage report, this may take a moment.
Code Coverage Report
2012-01-10 15:55:55
Summary:
Classes: 100.00% (2/2)
Methods: 100.00% (1/1)
Lines: 100.00% (5/5)
Foo
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 5/ 5)
Esto es lo que debe hacer para obtener una declaración de cambio del 100% de cobertura:
Asegúrese de que haya al menos una prueba que envíe un caso que no existe.
Entonces, si tienes:
switch ($name) {
case ''terry'':
return ''blah'';
case ''lucky'':
return ''blahblah'';
case ''gerard'':
return ''blahblah'';
}
asegúrese de que al menos una de sus pruebas envíe un nombre que no sea ni terry
ni lucky
ni gerard
.
Gran parte del problema aquí es la insistencia en obtener una cobertura de ejecución del 100% de "líneas". (A los gerentes les gusta esta idea, es un modelo simple que pueden entender). Muchas líneas no son "ejecutables" (espacios en blanco, espacios entre declaraciones de funciones, comentarios, declaraciones, "sintaxis pura", por ejemplo, el cierre "}" de un interruptor o declaración de clase, o declaraciones complejas divididas entre múltiples líneas de origen).
Lo que realmente quieres saber es "¿está cubierto todo el código ejecutable ?" Esta distinción parece tonta pero conduce a una solución. XDebug rastrea lo que se ejecuta, bueno, por número de línea y su esquema basado en XDebug informa los rangos de líneas ejecutadas. Y obtienes los problemas discutidos en este hilo, incluidas las soluciones klunky de tener que anotar el código con comentarios de "no me cuentes", poner "}" en la misma línea que la última declaración ejecutable, etc. Ningún programador es realmente dispuesto a hacer eso y mucho menos mantenerlo.
Si uno define código ejecutable como ese código que puede ser llamado o controlado por un condicional (lo que el compilador llama "bloques básicos"), y el seguimiento de la cobertura se realiza de esa manera, entonces el diseño del código y los casos tontos simplemente desaparece Una herramienta de cobertura de prueba de este tipo recopila lo que se denomina "cobertura de sucursal", y puede obtener o no 100% de "cobertura de sucursal" literalmente al ejecutar todo el código ejecutable. Además, retomará esos casos divertidos donde tienes un condicional dentro de una línea (usando "x? Y: z") o en el que tienes dos declaraciones convencionales en una línea (por ejemplo,
if (...) { if (...) stmt1; else stmt2; stmt3 }
Como XDebug rastrea por línea, creo que trata esto como una declaración, y considera que es una cobertura si el control llega a la línea, cuando de hecho hay 5 partes para probar.
Nuestra herramienta de cobertura de prueba PHP implementa estas ideas. En particular, entiende que el código que sigue a una declaración de devolución no es ejecutable, y le indicará que no lo ha ejecutado, si no está vacío. Eso hace que el problema original del OP desaparezca. No más juegos para obtener números de cobertura "reales".
Al igual que con todas las opciones, a veces hay un inconveniente. Nuestra herramienta tiene un componente de instrumento de código que solo se ejecuta en Windows; El código PHP instrumentado puede ejecutarse en cualquier lugar y el procesamiento / visualización se realiza mediante un programa Java independiente de la plataforma. Entonces esto podría ser incómodo para el sistema OSX de OP. El instrumentador funciona bien en todos los sistemas de archivos compatibles con NFS, por lo que podría decirse que puede ejecutar el instrumentador en una PC e instrumentar sus archivos OSX.
Este problema particular fue planteado por alguien tratando de aumentar sus números de cobertura; el problema era en mi humilde opinión artificial y se puede curar dando un paso alrededor de la artificialidad. Hay otra forma de aumentar sus números sin escribir más pruebas, y eso es encontrar y eliminar código duplicado. Si elimina los duplicados, hay menos código para probar y probar una (no) copia en los efectos prueba la (otra copia inexistente) por lo que es más fácil obtener números más altos. Puedes leer más sobre esto aquí.