pruebas - phpunit tutorial
PHPUnit tiempo de ejecuciĆ³n de pruebas de impresiĆ³n (10)
¿Hay alguna manera de imprimir el tiempo de ejecución de cada prueba con PHPUnit?
Aquí hay un ejemplo completo basado en la idea de los edorianos. Probado en PHPunit 4.
Crea la siguiente clase de PHP:
class ProfilingTestListener extends PHPUnit_Framework_BaseTestListener
{
public function endTest(PHPUnit_Framework_Test $test, $time)
{
printf("Test ''%s'' ended./tTotal time %s s./tTest time %s s./n",
str_pad($test->toString(), 50),
number_format($test->getTestResultObject()->time(), 3),
number_format($time, 3)
);
}
}
Agregue lo siguiente a su phpunit.xml:
<phpunit ..>
...
<listeners>
<listener class="ProfilingTestListener"></listener>
</listeners>
...
</phpunit>
Ejemplo de salida:
PHPUnit 4.7.7 by Sebastian Bergmann and contributors.
Test ''FooTest::testFoo '' ended. Total time 2.050 s. Test time 0.026 s.
.Test ''FooTest::testBar '' ended. Total time 2.077 s. Test time 1.000 s.
.Test ''FooTest::testBar2 '' ended. Total time 3.077 s. Test time 0.730 s.
Bueno, puedes hacer que exporte el tiempo de ejecución con Logging . No se muestra directamente como resultado, pero podría escribir un visor de informes bonito que generaría los resultados del archivo de registro (ya sea desde JSON o XML). Eso debería conseguirte lo que quieres ...
En mi opinión, la solución más sencilla es exportar estadísticas de prueba como json:
$ phpunit --log-json testExport.json
Me gustó la respuesta de @adri. Me puse en esto:
alias phpunittime=" | awk ''/$NF ~ ''/,/'' && /$1 ~ //"(test|time)/"/'' /
| cut -d: -f2- /
| sed /"N;s//n/--//" /
| sed /"s/,///" /
| awk ''BEGIN{FS=/"--/"}; {print /$2 /$1}'' | sort -r /
| head"
Para usarlo, deberá configurar la unidad PHP para generar un archivo de registro JSON. Para hacerlo, haz que tu phpunit.xml
vea así:
<phpunit>
<logging>
<log type="json" target="/tmp/logfile.json"/>
</logging>
</phpunit>
Entonces use así:
$ cat /tmp/logfile.json | phpunittime
Para ver más o menos de 10 tiempos, digamos 2 o 19, use -n 2
o -n 19
, respectivamente, al final.
Lo bueno de esto es que no hace suposiciones sobre cómo llamas / ejecutas phpunit (en mi caso, uso CakePHP y ejecuto mi comando de esta manera: la Console/cake test app
). Además, puede ejecutar sus pruebas y ver su salida como normal ... su terminal no se queda allí hasta que se realizan las pruebas.
Muchas de las respuestas actuales discuten cómo acceder y analizar los tiempos de duración en el archivo de registro. Compartiré dos formas de modificar la salida de la CLI en phpUnit versión 3.7.38 (que es lo que Travis-CI usa para PHP por defecto), basándose en la de @edorian.
Utilice una impresora personalizada para anular la salida de CLI. No puedo encontrar ninguna documentación para las impresoras, pero parecen ser compatibles. Puedes ver qué métodos están disponibles en el código fuente .
class TestDurationPrinter extends PHPUnit_TextUI_ResultPrinter
{
public function endTest(PHPUnit_Framework_Test $test, $time)
{
printf("Test ''%s'' ended and took %s seconds./n",
$test->getName(),
$time
);
}
}
Luego agregue estas líneas como atributos a phpunit
en el archivo phpunit.xml
:
printerFile="path/to/TestDurationPrinter.php"
printerClass="TestDurationPrinter"
También puede usar la opción --printer
CLI pero eso no funciona bien con los espacios de nombres.
Puede agregar a la salida de la CLI, en lugar de anularla, con un TestListener implementando la interfaz PHPUnit_Framework_TestListener
(esta es la misma interfaz que usan las impresoras). Esto todavía se imprimirá .
, S
y F
así que asegúrate de dar cuenta de eso, si lo deseas.
class TestDurationListener implements PHPUnit_Framework_TestListener
{
public function endTest(PHPUnit_Framework_Test $test, $time)
{
printf("Test ''%s'' ended and took %s seconds./n",
$test->getName(),
$time
);
}
public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
{
}
public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
{
}
public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
}
public function addRiskyTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
}
public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
}
public function startTest(PHPUnit_Framework_Test $test)
{
}
public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
{
}
public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
{
}
}
En la versión 3.8 y superior hay un PHPUnit_Framework_BaseTestListener
que puede extenderse para que solo defina los métodos que desea anular.
class TestDurationListener extends PHPUnit_Framework_BaseTestListener
{
public function endTest(PHPUnit_Framework_Test $test, $time)
{
printf("Test ''%s'' ended./n", $test->getName());
}
}
Para incluir su nuevo oyente, agregue estas líneas a su archivo phpunit.xml
:
<listeners>
<listener class="TestDurationListener" file="path/to/TestDurationListener.php" />
</listeners>
Para añadir algunas formas más:
Puede escribir un escucha de prueba personalizado y agregarlo al archivo XML . En ese oyente puede acceder a $testResult->time()
. Algunas líneas en su phpunit.xml y una clase de PHP de 10 líneas. No demasiada molestia.
class SimpleTestListener implements PHPUnit_Framework_TestListener
{
public function endTest(PHPUnit_Framework_Test $test, $time)
{
printf("Test ''%s'' ended and took %s seconds./n",
$test->getName(),
$test->time()
);
}
}
De todos modos, si genera un junit.xml (para CI o al mismo tiempo para crear una cobertura de código), todos los números están allí y con un XSLT simple puede hacer que esos sean aún más legibles.
Ejemplo junit.xml
<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
<testsuite name="DemoTest" file="/home/edo/foo.php" tests="2" assertions="2" failures="1" errors="0" time="0.007727">
<testcase name="testPass" class="DemoTest" file="/home/edo/foo.php" line="4" assertions="1" time="0.003801"/>
<testcase name="testFail" class="DemoTest" file="/home/edo/foo.php" line="8" assertions="1" time="0.003926">
<failure type="PHPUnit_Framework_ExpectationFailedException">DemoTest::testFail
Failed asserting that <boolean:false> is true.
/home/edo/foo.php:9
</failure>
</testcase>
</testsuite>
</testsuites>
Y con una transformación como esta:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h1>Tests</h1>
<xsl:for-each select="testsuites/testsuite">
<h2><xsl:value-of select="@name"/></h2>
<ul>
<xsl:for-each select="testcase">
<li>
<xsl:value-of select="@name"/> : <xsl:value-of select="@time"/>
<xsl:if test="failure">
<b>Failed !</b>
<i><xsl:value-of select="*"/></i>
</xsl:if>
</li>
</xsl:for-each>
</ul>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
obtiene líneas que le muestran: <li>testPass : 0.003801</li>
(el HTML es solo un ejemplo, debería ser fácilmente adaptable).
Haciendo referencia a mi propia publicación de blog aquí: http://edorian.github.io/2011-01-19-creating-your-custom-phpunit-output.formats/ para las cosas de xslt.
Si no te gusta escribir un Testlistener, como ya se sugirió, puedes usar el siguiente script para analizar el Resultado de prueba JSON de la PHPUnit en un formato más fácil de leer:
alias phpunit-report-runtime="phpunit --log-json php://stdout /
| awk ''/$NF ~ ''/,/'' && /$1 ~ //"(test|time)/"/'' /
| cut -d: -f2- /
| sed /"N;s//n/--//" /
| sed /"s/,///" /
| awk ''BEGIN{FS=/"--/"}; {print /$2 /$1}'' | sort -r /
| head -n 5"
El formato es <time in seconds>, <test method>
. Ejemplo de salida:
$ phpunit-report-runtime
0.29307007789612, "VCR//Util//SoapClientTest::testDoRequestHookDisabled"
0.16475319862366, "VCR//CassetteTest::testRecordAndPlaybackRequest"
0.092710018157959, "VCR//Util//SoapClientTest::testDoRequest"
0.031861782073975, "VCR//LibraryHooks//SoapTest::testShouldInterceptCallWhenEnabled"
0.026772022247314, "VCR//LibraryHooks//AbstractFilterTest::testRegisterAlreadyRegistered"
Simplemente agregue --log-junit "my_tests_log.xml" y luego abra este archivo con la aplicación de hoja de cálculo (Excel, Numbers, Calc) para verlo. Obtiene toda la información que solicita y puede ordenar por tiempo de ejecución de prueba.
Supongo que podría usar los métodos setUp
y tearDown
(que se llaman al principio y al final de cada prueba, respectivamente) para:
- Registre la hora actual antes de la prueba, en
setUp
, - Y calcule el tiempo que tomó la prueba, en
tearDown
.
Por supuesto, tendrás que hacer esto en cada una de tus clases de prueba, o en una súper clase que será heredada por todas tus clases de prueba.
Puede implementar su propio corredor de prueba, por ejemplo, ampliando PHPUnit_TextUI_TestRunner
y hacerlo recopilar e imprimir los tiempos de ejecución.