2011-10-09 7 views
11

Tengo un conjunto complejo de pruebas de PHPUnit, algunas de las cuales implican la conexión a servidores de todo el mundo que, por alguna razón, a veces agota el tiempo de espera.PHPUnit: reintenta automáticamente las pruebas fallidas X veces?

En lugar de hacer que la prueba falle cuando el servidor agote el tiempo de espera, me gustaría simplemente volver a intentar esa prueba una o más veces antes de marcarla realmente como fallida.

Ahora, entiendo que esta puede no ser la mejor manera de manejar mi situación actual. Una mejor solución sería arreglar los servidores. Pero, esto está fuera de mi control ahora mismo.

Así que, lo que realmente me gustaría, es una forma de decirle a PHPUnit que vuelva a probar cada caso de prueba que falla X veces, y solo marque como fallido si falla cada vez.

¿Alguna idea?

Editar: Muchos de ustedes han respondido con útiles sugerencias de que no hagan esto. Entiendo, gracias. Sin embargo, específicamente lo que intento hacer es crear un conjunto de pruebas que pruebe el funcionamiento del sistema completo , incluidos los servidores remotos. Entiendo el concepto de probar ciertas partes de mi código con respuestas "falsas" desde el exterior ... pero también duermo mejor por la noche si parte de mis pruebas prueban la "pila completa".

+2

Según su edición: 1. Cuando diga "no es su anfitrión" dirá "no es parte de _su_sistema". Por lo tanto, no debe incluirlo en su prueba, porque de todos modos no puede influir y falsificará los resultados. 2. Nunca crearías una prueba '$ this-> assertEquals (1, rand (0,1))', ¿verdad? Eso es lo que sucede cuando incluyes sistemas externos inciertos. – KingCrunch

Respuesta

10

Como PHPUnit no es compatible con este comportamiento de la caja, deberá codificar el bucle usted mismo. En lugar de hacerlo en cada prueba que lo requiera, cree una clase base de caso de prueba personalizada (si no lo ha hecho) que extienda PHPUnit_Framework_TestCase y proporcione la característica.

Usted puede conseguir la suposición y anular testBare() para comprobar si hay una anotación como @retry 5, bucle de ese número de veces, llamando parent::testBare(), y tragar todas las excepciones (o un subconjunto) excepto el último.

public function runBare() { 
    // I'll leave this part to you. PHPUnit supplies methods for parsing annotations. 
    $retryCount = $this->getNumberOfRetries(); 
    for ($i = 0; $i < $retryCount; $i++) { 
     try { 
      parent::runBare(); 
      return; 
     } 
     catch (Exception $e) { 
      // last one thrown below 
     } 
    } 
    if ($e) { 
     throw $e; 
    } 
} 

O puede crear un método de ayuda similar que lleva el número de reintentos y un cierre/exigible como parámetros y lo llaman de cada prueba que lo necesita.

public function retryTest($count, $test) { 
    // just like above without checking the annotation 
    ... 
     $test(); 
    ... 
} 

public function testLogin() { 
    $this->retryTest(5, function() { 
     $service = new LoginService(); 
     ... 
    }); 
} 
+0

Hola David, ¿Podrías por favor proporcionar más detalles sobre qué hacer? Tengo que volver a intentar el caso de prueba una vez si se produjo un error. – Deep123

+0

@ Deep123 ¿Qué parte no está clara? –

+0

Gracias por responder David. Quiero simplemente volver a intentar mi caso de prueba si se produjo un error sin el uso de ninguna anotación. Lo que hice ... Pongo el código de la función ejecutar desnudo [como se define en tu respuesta] en mi clase base usando $ retryCount = 2, después de este punto no estoy claro :( – Deep123

7

No es exactamente una respuesta a su pregunta, pero lo diré de todos modos: sus pruebas nunca deben incluir recursos remotos (especialmente cuando están completamente fuera de su alcance (a diferencia de los espejos locales)). Debe encapsular sus conexiones en clases separadas (por ejemplo, Connection) y dentro de sus pruebas simular esos objetos y trabajar con respuestas estáticas, que sus hosts remotos devolverían.

+1

Esto es cierto para las pruebas unitarias, pero para las pruebas de aceptación automatizadas, todavía hay mucho debate sobre si se burlan o no de los servicios externos. Elegimos no hacerlo, y puede aumentar la fragilidad de una prueba. En tales casos, los intentos pueden ser útiles. –

1

No creo que haya un soporte para eso, alguien puede probar que estoy equivocado, pero me sorprendería en ese caso.

Creo que lo que puedes hacer es en lugar de afirmar de inmediato en los métodos de prueba que se recuperarán, se repite X veces y se iniciará con éxito, fuera del ciclo se confirmará el resultado.

De esta forma simple, que ya había pensado, tiene la desventaja de agregar más código a cada método de prueba. Si tiene muchos de ellos, aumenta la carga de mantenimiento.

De lo contrario, si desea automatizar más, puede implementar un PHPUnit_Framework_TestListener, mantener un recuento de las pruebas fallidas en el conjunto asociativo y comparar con las ejecuciones de prueba. No estoy seguro de qué tan factible es esta ruta, pero podría intentarlo.

0

Debería poder crear una aserción de conexión DB e implementar esa prueba en sus otras pruebas "como" su conexión DB. Dentro de esa prueba, puedes intentar tantas veces como necesites y devolver el resultado falso después de que X lo intente.

3

En lugar de conectarse a servidores en vivo, ¿no debería usar objetos y accesorios falsos para que las respuestas de otros lugares no tengan un efecto en sus pruebas?

Posiblemente pueda usar la inyección de dependencia para usar un cliente HTTP específico que le devolverá los datos y el código de respuesta que le indique (dependiendo de cómo se escriba su código). Idealmente, las pruebas de su unidad deben ser independientes de las influencias externas; usted debe tener el control de lo que está probando, y forzar un error 404 o 500, por ejemplo, debe ser una parte separada de sus pruebas.

En lugar de tratar de hackear las pruebas no deterministas, lo mejor sería examinar si puede modificar su código para habilitar el simulacro y los accesorios de prueba.

Aparte de eso, que ya conoces por supuesto, me temo que no conozco una forma de decirle a PHPUnit que permita que falle una prueba. Parece completamente contrario a lo que la herramienta debería estar haciendo.

+0

+1, y la última frase importante: "Parece completamente contrario a lo que la herramienta debería estar haciendo". – hakre

Cuestiones relacionadas