example - ¿Cómo probar un servicio web en PHPUnit a través de múltiples pruebas?
phpunit tutorial (6)
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 usando el método getMockFromWsdl
que se describe aquí:
Sin embargo, dado que quiero probar varios métodos de esta misma clase, cada vez que configuro el objeto, también tengo que configurar el objeto WSDL SoapClient falso . Esto está provocando un error fatal:
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 usar el mismo objeto de prueba en varias pruebas sin tener que volver a generarlo en el WSDL? Eso parece ser un problema.
-
Después de haber pedido que publiquemos algún código para ver, este es 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);
}
Para el uso básico, algo como esto funcionaría. 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
}
?>
Alternativamente, probablemente 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);
}
?>
¿Por qué está creando el simulacro en setUp () si el objetivo es obtener una definición de clase simulada una vez por ejecución de un archivo de prueba completo? Si recuerdo correctamente, se ejecuta antes de cada prueba definida en "esta" clase de prueba ... Prueba setUpBeforeClass ()
De http://www.phpunit.de/manual/3.4/en/fixtures.html
Además, los métodos de plantilla setUpBeforeClass () y tearDownAfterClass () se invocan antes de ejecutar la primera prueba de la clase de caso de prueba y después de ejecutar la última prueba de la clase de caso de prueba, respectivamente.
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 necesita es agregar a la definición de Mock un nombre de clase propio, para que PHPUnit no cree un nombre automático, observe el segundo argumento para $ this-> getMockFromWsdl:
protected function setUp() {
parent::setUp();
$this->client = new Client();
$this->SoapClient = $this->getMockFromWsdl(
''service.wsdl'', ''MyMockClass''
);
$this->client->setClient($this->SoapClient);
}
Ahora puede crear tantos clientes como desee, solo cambie el nombre de clase para cada uno.
Esta no es una solución ideal, pero en su configuración le da a SOAP un nombre de clase "aleatorio", por ejemplo
$this->_soapClient = $this->getMockFromWsdl( ''some.wsdl'', ''SoapClient'' . md5( time().rand() ) );
Esto asegura que al menos cuando se llama a la configuración no se obtiene ese error.
Agregando mi $ .02 aquí ... Recientemente me encontré con esta misma situación y después de un poco de frustración aquí fue cómo pude 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 ''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 para getMockFromWsdl
, tuve que asegurarme de que le estaba pasando a cada uno un nombre único (por ejemplo, SoapClient_MyWorker
) o que eso haría que PHPUnit se cayera.
No estoy seguro si obtener el simulacro SOAP de una función estática y obtener acceso a la función getMockFromWsdl
al pasar $this
como un parámetro es la mejor manera de lograr esto, pero ya está.
Una forma de pasar un objeto de prueba a prueba en PHPUnits es con la dependencia de prueba, si la creación de instancias de un objeto en particular es demasiado exigente / consume mucho 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;
}
}
?>