2009-09-28 19 views
30

Data la seguente classe:PHPUnit: Verifica che array ha una chiave con dato valore

<?php 
class Example { 
    private $Other; 

    public function __construct ($Other) 
    { 
     $this->Other = $Other; 
    } 

    public function query() 
    { 
     $params = array(
      'key1' => 'Value 1' 
      , 'key2' => 'Value 2' 
     ); 

     $this->Other->post($params); 
    } 
} 

E questo TestCase:

<?php 
require_once 'Example.php'; 
require_once 'PHPUnit/Framework.php'; 

class ExampleTest extends PHPUnit_Framework_TestCase { 

    public function test_query_key1_value() 
    { 
     $Mock = $this->getMock('Other', array('post')); 

     $Mock->expects($this->once()) 
       ->method('post') 
       ->with(YOUR_IDEA_HERE); 

     $Example = new Example($Mock); 
     $Example->query(); 
    } 

Come faccio a verificare che $params (che è un array) e viene passato a $Other->post() contiene una chiave denominata "chiave1" che ha un valore di "Valore 1"?

Non voglio verificare tutto l'array - questo è solo un codice di esempio, nel codice effettivo l'array passato ha molti più valori, voglio verificare solo una singola coppia chiave/valore.

C'è $this->arrayHasKey('keyname') che posso utilizzare per verificare che la chiave esista.

C'è anche $this->contains('Value 1'), che può essere utilizzato per verificare che l'array abbia questo valore.

Potrei persino combinare questi due con $this->logicalAnd. Ma questo ovviamente non dà il risultato desiderato.

Finora ho usato returnCallback, catturando l'intero $ param e poi facendo affermazioni su questo, ma c'è forse un altro modo per fare ciò che voglio?

+1

$ questo-> attributo (Vincolo, valore) è in grado di fare ciò che sono dopo, ma non funziona sugli array. –

risposta

7

Ho finito per creare la mia classe di vincoli, basata sull'attributo uno

<?php 
class Test_Constraint_ArrayHas extends PHPUnit_Framework_Constraint 
{ 
    protected $arrayKey; 

    protected $constraint; 

    protected $value; 

    /** 
    * @param PHPUnit_Framework_Constraint $constraint 
    * @param string      $arrayKey 
    */ 
    public function __construct(PHPUnit_Framework_Constraint $constraint, $arrayKey) 
    { 
     $this->constraint = $constraint; 
     $this->arrayKey = $arrayKey; 
    } 


    /** 
    * Evaluates the constraint for parameter $other. Returns TRUE if the 
    * constraint is met, FALSE otherwise. 
    * 
    * @param mixed $other Value or object to evaluate. 
    * @return bool 
    */ 
    public function evaluate($other) 
    { 
     if (!array_key_exists($this->arrayKey, $other)) { 
      return false; 
     } 

     $this->value = $other[$this->arrayKey]; 

     return $this->constraint->evaluate($other[$this->arrayKey]); 
    } 

    /** 
    * @param mixed $other The value passed to evaluate() which failed the 
    *       constraint check. 
    * @param string $description A string with extra description of what was 
    *        going on while the evaluation failed. 
    * @param boolean $not Flag to indicate negation. 
    * @throws PHPUnit_Framework_ExpectationFailedException 
    */ 
    public function fail($other, $description, $not = FALSE) 
    { 
     parent::fail($other[$this->arrayKey], $description, $not); 
    } 


    /** 
    * Returns a string representation of the constraint. 
    * 
    * @return string 
    */ 
    public function toString() 
    { 
     return 'the value of key "' . $this->arrayKey . '"(' . $this->value . ') ' . $this->constraint->toString(); 
    } 


    /** 
    * Counts the number of constraint elements. 
    * 
    * @return integer 
    */ 
    public function count() 
    { 
     return count($this->constraint) + 1; 
    } 


    protected function customFailureDescription ($other, $description, $not) 
    { 
     return sprintf('Failed asserting that %s.', $this->toString()); 
    } 

Esso può essere utilizzato in questo modo:

... ->with(new Test_Constraint_ArrayHas($this->equalTo($value), $key)); 
+2

Richiesta di pull per quella funzione: https://github.com/sebastianbergmann/phpunit/pull/312 – cweiske

-2

Siamo spiacenti, non sono un oratore inglese.

Penso che si può verificare se una chiave esiste nella matrice con la funzione array_key_exists, ed è possibile verificare se il valore esiste con array_search

Ad esempio:

function checkKeyAndValueExists($key,$value,$arr){ 
    return array_key_exists($key, $arr) && array_search($value,$arr)!==false; 
} 

Usa !== perché array_search restituire la chiave di quel valore se esiste e potrebbe essere 0.

+6

So tutto, ma voglio impostare un assert in PHPUnit. –

15

Al posto di creare un riutilizzabile classe vincolo, ho potuto affermare il valore di una chiave array utilizzando il vincolo callback esistente in PHPUnit. Nel mio caso d'uso, avevo bisogno di verificare per un valore di matrice nel secondo argomento un metodo mocked (MongoCollection::ensureIndex(), se qualcuno è curioso). Ecco quello che mi si avvicinò con:

$mockedObject->expects($this->once()) 
    ->method('mockedMethod') 
    ->with($this->anything(), $this->callback(function($o) { 
     return isset($o['timeout']) && $o['timeout'] === 10000; 
    })); 

Il callback constraint aspetta una richiamabile nel suo costruttore, e semplicemente invoca durante la valutazione. L'asserzione passa o fallisce a seconda che il callable restituisca vero o falso.

Per un progetto di grandi dimensioni, consiglierei sicuramente di creare un vincolo riutilizzabile (come nella soluzione di cui sopra) o una richiesta di associazione per PR #312 da unire in PHPUnit, ma questo ha fatto il trucco per un'esigenza una tantum. È facile vedere come il vincolo di callback possa essere utile anche per asserzioni più complicate.

+0

è possibile mettere un 'assert *' all'interno del contra- re 'callback'? – jjoselon

30

Il metodo $this->arrayHasKey('keyname'); esiste ma il suo nome è assertArrayHasKey:

// In your PHPUnit test method 
$hi = array(
    'fr' => 'Bonjour', 
    'en' => 'Hello' 
); 

$this->assertArrayHasKey('en', $hi); // Succeeds 
$this->assertArrayHasKey('de', $hi); // Fails 
2

Nel caso in cui si desidera fare qualche prova complessa sul parametro, e hanno anche messaggi e confronti utili, c'è sempre la possibilità di asserzioni che immettono all'interno del callback.

ad es.

$clientMock->expects($this->once())->method('post')->with($this->callback(function($input) { 
    $this->assertNotEmpty($input['txn_id']); 
    unset($input['txn_id']); 
    $this->assertEquals($input, array(
     //... 
    )); 
    return true; 
})); 

Si noti che il callback restituisce true. Altrimenti, fallirebbe sempre.

Problemi correlati