2012-07-24 8 views
10

Ho un metodo di prova che dipende da un altro metodo che si utilizza un provider di dati in PHPUnit:Combinando dipendenze con i fornitori di dati

/** 
* @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); 
} 

Ho anche una funzione di provider di dati getFields(), non c'è bisogno di dimostrare che qui.

Il primo test che si basa sul fornitore di dati passa - $result NON è nullo.

Mi aspetto che il risultato del test venga passato al test dipendente come parametro $result. Tuttavia, la funzione testCanDoSomeMoreStuff riceve un parametro NULL e il test ha esito negativo.

Aggiornamento

Questo semplice test case viene illustrato il 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); 
    } 
} 

Come una soluzione, per ora, ho memorizzato il risultato in una proprietà statica tra i test.

+0

Hai provato 'print_r ($ results);' per vedere cosa viene passato a 'testCanDoSomeMoreStuff()'? – uzyn

+0

Ciao Uzyn, sì - null viene passato. Ho anche stampato il risultato della chiamata a "my_func", che non è nullo. – iainp999

+0

Il tuo codice mi sembra a posto. Forse potresti voler condividere il tuo codice attuale, potrebbero esserci degli errori nell'attuale. – uzyn

risposta

2

Il problema è il risultato di diversi fattori:

  • Ciascun valore viene memorizzato in un array utilizzando il nome della prova come chiave.
  • Il nome per un test che riceve i dati è <name> with data set #<x>.
  • L'annotazione @depends non accetta più parole.

C'è una soluzione alternativa per l'hacking: ignorare TestCase::getDataSetAsString per restituire un nome accettato dall'annotazione. Ciò è reso leggermente problematico dal momento che i campi obbligatori TestCase sono privati, ma con PHP 5.3.2+ è possibile aggirare il problema.

Importante: Purtroppo, non si può avere la prova di funzionamento dipendente per ogni riga di dati - solo una riga specifica. Se il tuo fornitore di dati restituisce solo una riga di dati, questo non è un problema.

Ecco il codice con un test di esempio. Si noti che non è necessario assegnare un nome alla riga di dati. Se si lascia la chiave 'foo', modificare @depends in 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); 
    } 
} 

Ovviamente, questa non è una soluzione a lungo termine. Sarebbe meglio se il test dipendente fosse eseguito una volta per ogni risultato del test dal metodo che riceve i dati. È possibile inviare una richiesta di funzionalità o richiamare la richiesta su PHPUnit.

+0

Grazie David, è molto utile. Ho riportato il problema su github ieri insieme al codice di esempio, quindi suppongo che per ora lo lascerò con loro. – iainp999

2

Se il $result in testCanDoSomeStuff() è davvero non null, allora questo dovrebbe lavoro.

a prendere questa parte, primo tentativo di semplificare senza il provider di dati, qualcosa di simile:

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); 
    } 
} 

Testing questo dovrebbe tradursi in qualcosa di simile ...

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

Ora aggiungere il fornitore di dati, sostituire la mia variabile semplice con la funzione e quindi testarla di nuovo.

Se questo risultato differisce, var_dump la variabile $result prima di restituirlo in testcase testCanDoSomeStuff(). Se non è null lì, bug the behaviour.

+0

Ciao Bjoern. Scusa, avrei dovuto aggiungere che questo era esattamente quello che ho provato anche io, e ha funzionato. Grazie per il link, cercherò di ricreare il problema in una classe che posso inviare come parte della segnalazione di bug. – iainp999

2

Mi aspettavo anche che il problema descritto funzionasse e, dopo alcune ricerche, ho scoperto che questo non è un bug, ma un comportamento previsto, non documentato. Il test dipendente non conosce i set di dati restituiti dal provider ed è per questo che il parametro di test è nullo.

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

Il @dataProvider annotazioni vengono calcolati prima dell'esecuzione del test. Fondamentalmente, la fase di pre-test crea un metodo di test per ogni insieme di parametri forniti dal fornitore di dati. @depends dipende da ciò che è essenzialmente il prototipo del test guidato dai dati, quindi in un modo che @depends è su un test inesistente (non eseguito).

Un altro modo per pensarci, è che se il provider forniva più di un set di parametri. PHPUnit renderebbe molti metodi testDataProvider ma non ci sarebbero molti metodi testDataReceiver perché non esiste un metodo @dataProvider su quel metodo di test per la fase di pre-test.

Tuttavia è possibile avere @depends e @dataProvider sullo stesso metodo di prova. Basta fare attenzione a ottenere l'ordine dei parametri giusto, anche se in questo caso potrebbe non esserci un primo parametro.

In pratica, è necessario utilizzare i fornitori di dati quando il set di dati presenta più righe. Tuttavia, è sempre possibile utilizzare @depend e @dataProvider allo stesso tempo per ottenere più o meno lo stesso comportamento.

Problemi correlati