2012-07-24 11 views
10

Mam jedną metodę badawczą, która zależy od innej metody, która sama korzysta z usług transmisji danych w PHPUnit:Łączenie zależnościami z dostawcami danych

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

Mam też funkcję dostawcy getFields() danych, nie ma potrzeby, aby pokazać, że tutaj.

Pierwszy test, który opiera się na przekazach danych - $result NIE ma wartości NULL.

Oczekuję, że wynik testu zostanie przekazany do testu zależnego jako parametr $result. Jednak funkcja testCanDoSomeMoreStuff odbiera parametr NULL, a test kończy się niepowodzeniem.

Aktualizacja

Ten prosty sprawdzian demonstruje problem:

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

jako obejście do teraz, mam zapisany wynik w nieruchomości statycznego pomiędzy testami.

+0

Czy wypróbowałeś 'print_r ($ results);' aby sprawdzić, co jest przekazywane do 'testCanDoSomeMoreStuff()'? – uzyn

+0

Hi Uzyn, tak - minęło zero. Wydrukowałem także wynik wywołania funkcji "my_func", która nie jest pusta. – iainp999

+0

Twój kod wygląda dobrze dla mnie. Być może zechcesz podzielić się swoim faktycznym kodem, bo w rzeczywistości mogą występować błędy. – uzyn

Odpowiedz

2

Problemem jest wynikiem kilku czynników:

  • Każdy wynik testu jest przechowywana w tablicy przy użyciu nazwy testu, jako klucz.
  • Nazwa testu, który otrzymuje dane, to <name> with data set #<x>.
  • Adnotacja @depends nie przyjmuje wielu słów.

Istnieje hacky: obejść TestCase::getDataSetAsString, aby zwrócić nazwę, którą zaakceptuje adnotacja. Jest to nieco problematyczne, ponieważ wymagane pola TestCase są prywatne, ale z PHP 5.3.2+ możesz to obejść.

Ważne: Niestety, nie można mieć na utrzymaniu próbny dla każdy wiersz danych - tylko jeden konkretny wiersz. Jeśli dostawca danych zwraca tylko jeden wiersz danych, nie stanowi to problemu.

Oto kod z próbnym testem. Pamiętaj, że nie musisz podawać nazwy swojego wiersza danych. Jeśli zostawisz klucz 'foo', zmień @depends na 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); 
    } 
} 

Oczywiście nie jest to rozwiązanie długoterminowe. Byłoby lepiej, gdybyś mógł wykonać test zależny raz dla każdego wyniku testu z metody otrzymywania danych. Możesz przesłać żądanie funkcji lub polecenie ściągnięcia do PHPUnit.

+0

Dzięki David, to bardzo przydatne. Zgłosiłem wczoraj problem na github wraz z przykładowym kodem, więc myślę, że zostawię to na teraz. – iainp999

2

Jeśli Twój $result w testCanDoSomeStuff() jest naprawdę nie null, to powinien praca.

Aby to rozbierać, najpierw spróbuj uprościć go bez dostarczającego dane, mniej więcej tak:

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

Testowanie powinno to doprowadzić do czegoś jak ...

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

Teraz dodaj dostawca danych, zamień moją prostą zmienną na twoją funkcję, a następnie przetestuj ją ponownie.

Jeśli ten wynik różni się, var_dump zmienna $result przed zwróceniem go w obudowie testowej testCanDoSomeStuff(). Jeśli nie jest to null, tam, null.

+0

Cześć Bjoern. Przepraszam, powinienem był dodać, że to było dokładnie to, co próbowałem, i zadziałało. Dziękuję za link. Postaram się odtworzyć problem w klasie, którą mogę zgłosić jako część raportu o błędzie. – iainp999

2

Spodziewałem się również, że opisany problem zadziała, a po pewnych badaniach dowiedziałem się, że to nie jest błąd, ale oczekiwane, nie udokumentowane zachowanie. Test zależny nie wie o zestawach danych zwróconych przez dostawcę, dlatego parametr testowy ma wartość null.

Źródło: https://github.com/sebastianbergmann/phpunit/issues/183#issuecomment-816066

@dataProvider adnotacje się obliczonego przed wykonaniem testu. Zasadniczo, faza przed testem tworzy metodę testową dla każdego zestawu parametrów dostarczanych przez dostawcę danych. @depends zależy od tego, co jest w istocie prototypem testu opartego na danych, więc w pewnym sensie @depends znajduje się na nieistniejącym (niezawartym teście).

Innym sposobem myślenia o tym, jest to, że jeśli dostawca dostarczał więcej niż jeden zestaw parametrów. PHPUnit wykonałoby wiele metod testDataProvider, ale nie byłoby tak wielu metod testDataReceiver, ponieważ nie istnieje metoda @dataProvider dla tej metody testowej dla fazy przed testowaniem.

Możesz jednak mieć @depends i @dataProvider w tej samej metodzie testu. Po prostu uważaj, aby uzyskać prawidłową kolejność parametrów, chociaż w tym przypadku może nie być pierwszego parametru.

Zasadniczo należy korzystać z dostawców danych, gdy zbiór danych ma wiele wierszy. Jednak zawsze można używać jednocześnie @depend i @dataProvider, aby uzyskać mniej więcej to samo zachowanie.

Powiązane problemy