2009-08-07 18 views
10

Estoy probando algunas unidades 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 mail quiero burlarme de la función PHPs mail. Estos son solo algunos ejemplos.burlarse de las funciones de PHP en pruebas unitarias

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 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 experiencia en la prueba del código 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 hace posible o más fácil?

Respuesta

10

No de forma automática. 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 insistes, puedes usar el runkit extension que cambia el modelo de programación de php para que puedas 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.

+0

Ya veo. Esperaba (pero no esperaba) tal respuesta. Realmente no insisto, ya que quiero simplificar y acelerar las pruebas, no hacerlo más complejo. ¡Gracias por su respuesta! – avdgaag

+0

Ahora [Mockery] (http://docs.mockery.io/en/latest/cookbook/mocking_hard_dependencies.html) parece el [camino a seguir] (http://stackoverflow.com/a/42158443/659788). – Franco

+1

@Franco No es para builtins. – troelskn

0

En el entorno PHP 5.3+ que puede solucionar la necesidad de utilizar runkit extensión por el pirateo de los espacios de nombres. El único requisito en el sentido de que las llamadas a funciones no utilizan un espacio de nombres totalmente 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 nice example with the mockery framework

+0

Puede usar [php-mock] (https: // github.com/php-mock/php-mock) para crear tales simulacros. –

1

Here is an interesting article que escribe acerca de cómo 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í código de un ejemplo, en la entrada del blog donde se burla la función time:

<?php 

namespace My\Namespace; 

use PHPUnit_Framework_TestCase; 

/** 
* Override time() in current namespace for testing 
* 
* @return int 
*/ 
function time() 
{ 
    return SomeClassTest::$now ?: \time(); 
} 

class SomeClassTest extends PHPUnit_Framework_TestCase 
{ 
    /** 
    * @var int $now Timestamp that will be returned by time() 
    */ 
    public static $now; 

    /** 
    * @var SomeClass $someClass Test subject 
    */ 
    private $someClass; 

    /** 
    * Create test subject before test 
    */ 
    protected function setUp() 
    { 
     parent::setUp(); 
     $this->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 esto es una buena manera de hacerlo, pero sin duda funciona bien y creo que vale la pena mencionar aquí. Podría ser algo de comida para una discusión ...

Cuestiones relacionadas