2012-07-24 14 views
10

que tienen un método de prueba que depende de otro método que en sí utiliza un proveedor de datos en PHPUnit:dependencias combinación con los proveedores de datos

/** 
* @dataProvider getFields 
*/ 
public function testCanDoSomeStuff($parm1, $parm2) { 
    $result = my_func($parm1, $parm2); 
    $this->assertNotNull($result); 

    return $result; 
} 

/** 
* @depends testCanDoSomeStuff 
*/ 
public function testCanDoSomeMoreStuff($result) { 
    $this->assertNotNull($result); 
} 

que también tienen una función de proveedor de datos getFields(), no hay necesidad de demostrar que aquí.

La primera prueba que se basa en los pases del proveedor de datos - $result NO es nula.

Espero que el resultado de la prueba se pase a la prueba dependiente como el parámetro $result. Sin embargo, la función testCanDoSomeMoreStuff recibe un parámetro NULL y la prueba falla.

actualización

Este caso simple prueba demuestra el problema:

class MyTest extends PHPUnit_Framework_TestCase { 

    /** 
    * @dataProvider myFunc 
    */ 
    public function testCanDoSomeStuff($value) { 
     $this->assertNotNull($value); 
     return $value; 
    } 

    /** 
    * @depends testCanDoSomeStuff 
    */ 
    public function testCanDoSomeMoreStuff($value) { 
     $this->assertNotNull($value); 
    } 

    /** 
    * Data provider function 
    */ 
    public function myFunc() { 
     $values = array('22'); 
     return array($values); 
    } 
} 

Como solución por ahora, me he guardado el resultado en una propiedad estática entre las pruebas.

+0

¿Has probado 'print_r ($ results);' para ver qué se está pasando a 'testCanDoSomeMoreStuff()'? – uzyn

+0

Hola Uzyn, sí, se está aprobando el nulo. También imprimí el resultado de la llamada a 'my_func', que no es nulo. – iainp999

+0

Tu código me parece bien. Quizás desee compartir su código real, puede haber algunos errores en el real. – uzyn

Respuesta

2

el problema es el resultado de varios factores:

  • Cada resultado de la prueba se almacenan en una matriz usando el nombre de la prueba como la clave.
  • El nombre para una prueba que recibe datos es <name> with data set #<x>.
  • La anotación @depends no acepta varias palabras.

Hay una solución hacky: anule TestCase::getDataSetAsString para devolver un nombre que la anotación aceptará. Esto se hace un poco problemático ya que los campos obligatorios TestCase son privados, pero con PHP 5.3.2+ puede evitarlos.

Importante: Por desgracia, no se puede tener la prueba de funcionamiento dependiente para cada fila de datos - sólo una fila específica. Si su proveedor de datos devuelve solo una fila de datos, esto no es un problema.

Aquí está el código con una prueba de muestra. Tenga en cuenta que no tiene que nombrar su fila de datos. Si deja fuera la clave 'foo', cambie @depends a testOne-0.

class DependencyTest extends PHPUnit_Framework_TestCase 
{ 
    /** 
    * @dataProvider data 
    */ 
    public function testOne($x, $y) { 
     return $x + $y; 
    } 

    public function data() { 
     return array(
      'foo' => array(1, 2), 
     ); 
    } 

    /** 
    * @depends testOne-foo 
    */ 
    public function testTwo($z) { 
     self::assertEquals(3, $z); 
    } 

    protected function getDataSetAsString($includeData = false) { 
     if (!$includeData && $this->getPrivateField('data')) { 
      return '-' . $this->getPrivateField('dataName'); 
     } 
     return parent::getDataSetAsString($includeData); 
    } 

    private function getPrivateField($name) { 
     $reflector = new ReflectionProperty('PHPUnit_Framework_TestCase', $name); 
     $reflector->setAccessible(true); 
     return $reflector->getValue($this); 
    } 
} 

Obviamente, esta no es una solución a largo plazo. Sería mejor que la prueba dependiente se ejecute una vez para cada resultado de prueba del método que recibe los datos. Puede enviar una solicitud de función o una solicitud de extracción a PHPUnit.

+0

Gracias David, eso es muy útil. Informé el problema en github ayer junto con el código de ejemplo, así que supongo que lo dejaré con ellos por ahora. – iainp999

2

Si su $result en testCanDoSomeStuff() es realmente no null, entonces esto debe trabajo.

aprovechar esta diferencia, en primer lugar tratar de simplificarlo sin el proveedor de datos, algo como esto:

class StackTest extends PHPUnit_Framework_TestCase { 
    public function testCanDoSomeStuff() { 
     $result = true; 
     $this->assertTrue($result); 
     return $result; 
    } 

    /** 
    * @depends testCanDoSomeStuff 
    */ 
    public function testCanDoSomeMoreStuff($result) { 
     $this->assertNotNull($result); 
    } 
} 

Prueba esto debe resultar en algo así como ...

~>phpunit test.php 
PHPUnit 3.6.11 by Sebastian Bergmann. 
.. 
Time: 1 second, Memory: 3.25Mb 
OK (2 tests, 2 assertions) 

Ahora agregue el proveedor de datos, reemplace mi variable simple con su función y luego vuelva a probarla.

Si este resultado es diferente, var_dump la variable $result antes de devolverla en la caja de prueba testCanDoSomeStuff(). Si no es null allí, bug the behaviour.

+0

Hola Bjoern. Lo siento, debería haber agregado que esto fue exactamente lo que también probé, y funcionó. Gracias por el enlace, intentaré recrear el problema en una clase que puedo enviar como parte del informe de errores. – iainp999

2

También esperaba que el problema descrito funcionara, y después de algunas investigaciones, descubrí que esto no es un error, sino un comportamiento esperado, no documentado. La prueba dependiente no conoce los conjuntos de datos devueltos por el proveedor, y es por eso que el parámetro de prueba es nulo.

Fuente: https://github.com/sebastianbergmann/phpunit/issues/183#issuecomment-816066

El @dataProvider anotaciones consiguen calculado antes de la ejecución de pruebas. Básicamente, la fase de prueba previa crea un método de prueba para cada conjunto de parámetros proporcionados por el proveedor de datos. Los @depends dependen de lo que es esencialmente el prototipo de la prueba basada en datos, de modo que @depends es inexistente (prueba no ejecutada).

Otra forma de pensarlo es que el proveedor está suministrando más de un conjunto de parámetros. PHPUnit haría que muchos métodos testDataProvider pero no habría tantos métodos testDataReceiver porque no hay un método @dataProvider en ese método de prueba para la fase de prueba previa.

Sin embargo, puede tener @depends y @dataProvider en el mismo método de prueba. Solo tenga cuidado de obtener el orden de los parámetros correctos, aunque en este caso puede no haber un primer parámetro.

Básicamente, debe utilizar los proveedores de datos cuando el conjunto de datos tiene varias filas. Sin embargo, siempre puede usar @depend y @dataProvider al mismo tiempo para lograr aproximadamente el mismo comportamiento.

Cuestiones relacionadas