2010-03-16 14 views
11

Estoy intentando probar una clase de interfaz de servicio web usando PHPUnit. Básicamente, esta clase realiza llamadas a un objeto SoapClient. Estoy intentando probar esta clase en PHPUnit utilizando el método getMockFromWsdl describe aquí:Cómo probar un servicio web en PHPUnit a través de pruebas múltiples?

http://www.phpunit.de/manual/current/en/test-doubles.html#test-doubles.stubbing-and-mocking-web-services

Sin embargo, ya que quiero probar varios métodos de esta misma clase, cada vez que la configuración del objeto, también tengo que configurar el simulacro WSDL SoapClient objeto. Esto está causando un error fatal que se lance:

Fatal error: Cannot redeclare class xxxx in C:\web\php5\PEAR\PHPUnit\Framework\TestCase.php(1227) : eval()'d code on line 15 

¿Cómo puedo utilizar el mismo objeto de burla a través de múltiples pruebas sin tener que regenerarlo fuera del WSDL cada vez? Eso parece ser un problema.

-

a haber sido invitado a publicar algo de código a la vista, aquí está el método de configuración en el TestCase:

protected function setUp() { 
    parent::setUp(); 

    $this->client = new Client(); 

    $this->SoapClient = $this->getMockFromWsdl(
     'service.wsdl' 
    ); 

    $this->client->setClient($this->SoapClient); 
} 

Respuesta

1

Para uso básico, algo como esto iba a funcionar. PHPUnit está haciendo magia detrás de escena. Si almacena en caché el objeto simulado, no se volverá a declarar. Simplemente cree una nueva copia de esta instancia en caché y debería estar listo para continuar.

<?php 
protected function setUp() { 
    parent::setUp(); 

    static $soapStub = null; // cache the mock object here (or anywhere else) 
    if ($soapStub === null) 
     $soapStub = $this->getMockFromWsdl('service.wsdl'); 

    $this->client = new Client; 
    $this->client->setClient(clone $soapStub); // clone creates a new copy 
} 
?>

Por otra parte, es probable que pueda almacenar en caché el nombre de la clase con get_class y luego crear una nueva instancia, en lugar de una copia. No estoy seguro de cuánto PHPUnit "mágico" está haciendo para la inicialización, pero vale la pena intentarlo.

<?php 
protected function setUp() { 
    parent::setUp(); 

    static $soapStubClass = null; // cache the mock object class' name 
    if ($soapStubClass === null) 
     $soapStubClass = get_class($this->getMockFromWsdl('service.wsdl')); 

    $this->client = new Client; 
    $this->client->setClient(new $soapStubClass); 
} 
?>
+0

he publicado algo de código en la pregunta para su revisión. Colocar en una clase_existe no parece que resolvería el problema, ya que todavía tienes que recuperar el objeto falso de alguna manera y esta clase siempre ejecutará esa evaluación. ¿A menos que tuviera que modificar PHPUnit? ¿Qué tienes en mente en dónde colocar el método class_exists()? – scraton

+0

No. Detener. PHPUnit no * * necesita modificación. Seriamente. ¿Por qué estás usando eval? La clase que ejecuta eval es el problema. La comprobación 'class_exists' es solo una sugerencia de hack para evitar la re-declaración de una clase preexistente. Esta comprobación debe realizarse dentro de la clase que realiza "eval". – pestilence669

+0

PHPUnit llama al código de evaluación, no a mi propio código. Creo que tiene algo que ver con cuando analiza el WSDL y crea objetos falsos fuera de esa definición. – scraton

1

Por qué estás creando la maqueta en la Configuración() si el punto es obtener definición de clase simulacro de una vez por ejecución del archivo de prueba de conjunto? Si no recuerdo mal se ejecuta antes de cada prueba se define en "esta" clase de prueba ... Trate setUpBeforeClass()

De http://www.phpunit.de/manual/3.4/en/fixtures.html

Además, el setUpBeforeClass() y tearDownAfterClass() métodos plantilla se llaman antes se ejecuta la primera prueba de la clase de caso de prueba y después de que se ejecuta la última prueba de la clase de caso de prueba, respectivamente.

-1

PHPUnit crea una clase para el simulacro basado en el WSDL. El nombre de clase, si no se proporciona, se construye a partir del nombre de archivo .wsdl, por lo que siempre es el mismo. En todas las pruebas, cuando intenta crear nuevamente la clase, se bloquea.

Lo único que se necesita es añadir a la definición falsa de un nombre de clase de su propio, por lo que PHPUnit no crea un nombre automático, observe el segundo argumento de $ this-> getMockFromWsdl:

protected function setUp() { 
    parent::setUp(); 

    $this->client = new Client(); 

    $this->SoapClient = $this->getMockFromWsdl(
     'service.wsdl', 'MyMockClass' 
    ); 

    $this->client->setClient($this->SoapClient); 
} 

Puede ahora crea tantos clientes como quieras, solo cambia el nombre de clase para cada uno.

+1

Esto tiene el mismo problema, en la segunda prueba se quejará hasta que se vuelva a declarar 'MyMockClass'. –

4

Esto no es una solución ideal, pero en su configuración dan el jabón se burlan de un nombre de clase "al azar", por ejemplo

$this->_soapClient = $this->getMockFromWsdl('some.wsdl', 'SoapClient' . md5(time().rand())); 

Esto asegura que al menos cuando la configuración que se llama no lo hacen obtener ese error

0

Adición de mi $ .02 aquí .. Hace poco me encontré con esta misma situación y después de un poco de frustración así es como yo era capaz de resolverlo:

class MyTest extends PHPUnit_Framework_TestCase 
    protected static $_soapMock = null; 

    public function testDoWork_WillSucceed() 
    { 
     $this->_worker->setClient(self::getSoapClient($this)); 
     $result = $this->_worker->doWork(); 
     $this->assertEquals(true, $result['success']); 
    } 

    protected static function getSoapClient($obj) 
    { 
     if(!self::$_soapMock) { 
      self::$_soapMock = $obj->getMockFromWsdl( 
       'Test/wsdl.xml', 'SoapClient_MyWorker' 
      ); 
     } 

     return self::$_soapMock; 
    } 
} 

Tengo muchos de los trabajadores ', cada uno en su propia clase de prueba y cada uno de los cuales necesita acceso a un objeto SOAP burlado. En el segundo parámetro, getMockFromWsdl, tuve que asegurarme de que cada uno de ellos pasara a un nombre único (por ejemplo, SoapClient_MyWorker) o que averiase PHPUnit.

No estoy seguro de si obtener el simulacro SOAP de una función estática y obtener acceso a la función getMockFromWsdl pasando $this como parámetro es la mejor manera de lograr esto, pero ya está.

0

Una manera de pasar un objeto de prueba a prueba en PHPUnits es la dependencia de prueba, si una instancia de un objeto en particular es demasiado exigente/tiempo:

<?php 
/** 
* Pass an object from test to test 
*/ 
class WebSericeTest extends PHPUnit_Framework_TestCase 
{ 

    protected function setUp() { 
     parent::setUp(); 
     // I don't know enough about your test cases, and do not know 
     // the implications of moving code out of your setup. 
    } 

    /** 
    * First Test which creates the SoapClient mock object. 
    */ 
    public function test1() 
    { 
     $this->client = new Client(); 

     $soapClient = $this->getMockFromWsdl(
      'service.wsdl' 
     ); 

     $this->client->setClient($this->SoapClient); 
     $this->markTestIncomplete(); 
     // To complete this test you could assert that the 
     // soap client is set in the client object. Or 
     // perform some other test of your choosing. 

     return $soapClient; 
    } 

    /** 
    * Second Test depends on web service mock object from the first test. 
    * @depends test1 
    */ 
    public function test1($soapClient) 
    { 
     // you should now have the soap client returned from the first test. 
     return $soapClient; 
    } 

    /** 
    * Third Test depends on web service mock object from the first test. 
    * @depends test1 
    */ 
    public function test3($soapClient) 
    { 
     // you should now have the soap client returned from the first test. 
     return $soapClient; 
    } 
} 
?> 
Cuestiones relacionadas