tutorial - Problema con PHPUnit y proveedores de datos
phpunit tutorial (6)
Tengo el siguiente caso de prueba:
include_once(''../Logger.php'');
class LoggerTest extends PHPUnit_Framework_TestCase {
public function providerLogger() {
return new Logger;
}
/**
* @dataProvider providerLogger
*/
public function testAddStream($logger) {
$this->assertTrue(false);
}
}
Cuando lo ejecuto en PHPUnit, obtengo:
PHPUnit 3.4.14 by Sebastian Bergmann.
..........
Time: 0 seconds, Memory: 5.75Mb
OK (1 tests, 0 assertions)
La prueba debería fallar, pero no lo hace. Traté de tener
public function providerLogger() {
return array(new Logger);
}
Pero me sale:
The data provider specified for LoggerTest::testAddStream is invalid.
Intenté declararlo static
(como dice el manual), pero aún así no hay diferencia.
Recuerdo haberlo hecho trabajando de manera similar antes, pero podría estar equivocado. ¿Qué me estoy perdiendo?
Gracias de antemano por tu ayuda.
PHPUnit 3.4.14 (tomado de PEAR) en PHP 5.3.3
¡He aquí que he logrado un patrón para lograr dependencias de prueba para los proveedores de datos! De esta manera usted puede encadenar proveedores de datos.
class ProviderDependencyTest extends PHPUnit_Framework_TestCase
{
private static $dataSet;
public function provideData()
{
self::$dataSet = array(
array(2,2,4),
array(1,0,2),
array(0,0,0)
);
//use static storage so you don''t have to call the dataProvider again
return self::$dataSet;
}
public function testProvideAdd()
{
$data = self::$dataSet;
$this->assertEquals(3,count($data[0]));
return $data[0];
}
/**
* @depends testProvideAdd
*/
public function testAdd($data)
{
$sum = $data[0] + $data[1];
$this->assertEquals($data[2], $sum);
return array($sum,$data[0],$data[1]);
}
/**
* @depends testAdd
*/
public function testSubtract($data)
{
$difference = $data[0] - $data[1];
$this->assertEquals($data[2], $difference);
return array($difference,$data[0],$data[1]);
}
/**
* @depends testSubtract
*/
public function testMultiply($data)
{
$product = $data[0] * $data[2];
$this->assertEquals($data[1], $product);
return $product;
}
/**
* @depends testMultiply
*
* @dataProvider provideData
*/
public function testMath($a,$b,$c)
{
//don''t redo the first set of tests
if(array($a,$b,$c) == self::$dataSet[0])
{
return;
}
$sum = $this->testAdd(array($a,$b,$c));
$difference= $this->testSubtract($sum);
$product = $this->testMultiply($difference);
$this->assertInternalType(''integer'', $product);
}
}
El segundo conjunto de datos falla 1 prueba para ilustrar.
Actualización menor: está bien usar métodos de instancia como proveedor desde la versión 3.2 (o en algún lugar alrededor de eso). Echa un vistazo a los comentarios.
El proveedor debe tener este aspecto.
public static function providerLogger() {
return array(
array(new Logger)
);
}
En primer lugar: el método debe ser estático si está utilizando una versión de phpunit inferior a 3.3.
La matriz s es importante. No es tan difícil de entender. La matriz externa tiene un valor para cada iteración a la que se debe llamar la prueba. Aquí la prueba acaba de ser llamada una vez. Las matrices internas son los parámetros (en orden) con los que se invoca la prueba. Su prueba espera exactamente un parámetro, por lo que las matrices internas siempre necesitan exactamente un valor. Otro pequeño ejemplo
public static function addTestProvider () {
return array(
/* First + Second = third? */
array(1,4,5),
array(3,3,6),
array(5,5,6)
);
}
public function testAdd ($a, $b, $result) {
$this->assertEquals($result, $a + $b);
}
Aquí, testAdd se ejecuta 3 veces, una para cada matriz de segundo nivel, y recibirá los valores de la matriz interna. Puede notar que la prueba fallará y le proporcionará un mensaje en el que la iteración del conjunto de datos (aquí # 3, porque 5 + 5 no es 6;)) falló la afirmación.
Elimine el parámetro de la función pública testAddStream ($ logger) e intente nuevamente. No creo que PHPUnit invoque una prueba que requiera parámetros que no pueda pasar.
También he descubierto que no puede encadenar directamente a los proveedores de datos:
class ProviderTest extends PHPUnit_Framework_TestCase {
public function provider() {
return array(array(''test''));
}
/**
* @dataProvider provider
*/
public function providerTest1($test) {
$this->assertTrue($test);
return array(array($test));
}
/**
* @dataProvider providerTest1
*/
public function providerTest2($test) {
$this->assertEquals(''test'', $test);
}
}
Al parecer, PHPUnit llama a todas las funciones del proveedor antes de ejecutar cualquier prueba, por lo que ni siquiera puede usar funciones del proveedor por separado para enviar datos de resultados de prueba a otras pruebas. Lo mejor que puedes hacer es simular:
class ProviderTest extends PHPUnit_Framework_TestCase {
private $provider_data = array();
public function provider() {
return array(array(''test''));
}
/**
* @dataProvider provider
*/
public function testProvider1($test) {
$this->assertFalse(empty($test));
array_push($this->provider_data, array($test));
}
/**
* @depends testProvider1
*/
public function testProvider2($test = NULL) {
if(is_null($test)) {
// simulate a provider
foreach($this->provider_data as $row) {
call_user_func_array(array($this, __METHOD__), $row);
}
} else {
$this->assertEquals(''test'', $test);
}
}
}
Tuve el mismo problema, y se resolvió, cuando eliminé el constructor vacío, se generó automáticamente. No estoy seguro de por qué esto resuelve el problema. Tampoco tuve ningún método de prueba llamado como la clase. El método del proveedor no necesita ser estático, hasta ahora mi prueba se ejecuta sin estática. Pero también se ejecuta cuando hago el método del proveedor estático
<?php
require_once ''calculator.php'';
/**
* Calculator test case.
*/
class CalculatorTest extends PHPUnit_Framework_TestCase {
/**
* @var Calculator
*/
private $Calculator;
/**
* Prepares the environment before running a test.
*/
protected function setUp() {
parent::setUp ();
// TODO Auto-generated CalculatorTest::setUp()
$this->Calculator = new Calculator(/* parameters */);
}
/**
* Cleans up the environment after running a test.
*/
protected function tearDown() {
// TODO Auto-generated CalculatorTest::tearDown()
$this->Calculator = null;
parent::tearDown ();
}
/**
* Constructs the test case.
*/
public function __construct() {
// TODO Auto-generated constructor
}
/**
* Tests Calculator->add()
*
* @dataProvider provider
*/
public function testAdd($a, $b, $c) {
// TODO Auto-generated CalculatorTest->testAdd()
//$this->markTestIncomplete ( "add test not implemented" );
//$this->Calculator->add(/* parameters */);
$this->assertEquals($this->Calculator->add($a, $b), $c);
}
public static function provider()
{
return array(
array(1, 1, 1),
array(1, 1, -1),
array(4, 2, 2),
array(1, 1, 1)
);
}
}
es el conjunto completo de código