Burlarse de las funciones de PHP en pruebas unitarias

Estoy probando un poco de código PHP con SimpleTest y me he encontrado con problemas. En mis pruebas de una clase de base de datos, quiero poder establecer una expectativa para las funciones de PHP mysql . En mis pruebas de una clase contenedora para la función de mail , quiero burlar la función de mail PHP. Estos son solo algunos ejemplos.

El punto es: no (siempre) quiero probar si mi clase de correo envía un correo electrónico, quiero probar cómo llama a la función de mail . Quiero poder controlar el retorno de estas funciones. Quiero poder probar mi clase de base de datos sin necesidad de una base de datos, accesorios y todo eso.

Tengo algo de experiencia en probar el código de Ruby, y Test :: Unit y RSpec hacen que sea muy fácil probar el código de forma aislada. Soy nuevo en las pruebas de PHP y parece que estoy probando mucho más de lo necesario, para que mis exámenes puedan pasar.

¿Hay alguna manera en SimpleTest o PhpUnit o en algún otro marco de prueba que lo haga posible o más fácil?

No de forma automatizada. Lo que puede hacer es escribir su código de forma tal que las dependencias externas se envuelvan en objetos que se envían desde el exterior. En su entorno de producción, simplemente conectará los adaptadores reales, pero durante la prueba, puede cablearlos a trozos o burlas.

Si realmente insiste, puede usar la extensión runkit que cambia el modelo de progtwigción de php para que pueda redefinir clases y funciones en tiempo de ejecución. Esta es una extensión externa y no estándar sin embargo, así que tenlo en cuenta. El estándar de facto es un enfoque manual como describí anteriormente.

Aquí hay un interesante artículo que escribe sobre burlarse de las funciones globales de php. El autor propone una solución muy creativa para ‘simular’ (kind off) las funciones globales de PHP sobrescribiendo los métodos dentro del espacio de nombres del SUT (servicio bajo prueba).

Aquí el código de un ejemplo en la publicación del blog donde se burla la función de time :

 someClass = new SomeClass; } /** * Reset custom time after test */ protected function tearDown() { self::$now = null; } /* * Test cases */ public function testOneHourAgoFromNoon() { self::$now = strtotime('12:00'); $this->assertEquals('11:00', $this->someClass->oneHourAgo()); } public function testOneHourAgoFromMidnight() { self::$now = strtotime('0:00'); $this->assertEquals('23:00', $this->someClass->oneHourAgo()); } } 

No estoy seguro si esta es una buena manera de hacerlo, pero seguramente funciona bien y creo que vale la pena mencionar aquí. Podría ser algo de comida para una discusión …

Existe una extensión PHPUnit que usa runkit internamente, y es capaz de usar asignadores de invocación, restricciones de parámetros y todo lo que un objeto burlado puede hacer.

https://github.com/tcz/phpunit-mockfunction

En el entorno PHP 5.3+, puede solucionar la necesidad de utilizar la extensión runkit pirateando los espacios de nombres. El único requisito en el sentido de que las llamadas a funciones no utilizan un espacio de nombres completamente calificado como \mysql_query() – y generalmente no lo hacen. Luego puede definir la misma función en su prueba, definiendo la prueba en un espacio de nombres, y PHP llamará a su función en lugar de a la función global. Personalmente utilizo este enfoque para stub la llamada a la función time() . Aquí hay un buen ejemplo con el marco de la burla