web-dev-qa-db-fra.com

PHPUnit: vérifier que le tableau a une clé avec une valeur donnée

Compte tenu de la classe suivante:

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

Et ce 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();
    }

Comment puis-je vérifier que $params (Qui est un tableau) et est passé à $Other->post() contient une clé nommée 'key1' qui a une valeur de 'Value 1'?

Je ne veux pas vérifier tout le tableau - c'est juste un exemple de code, dans le code réel, le tableau passé a beaucoup plus de valeurs, je veux vérifier juste une seule paire clé/valeur là-dedans.

Il y a $this->arrayHasKey('keyname') que je peux utiliser pour vérifier que la clé existe.

Il existe également $this->contains('Value 1'), qui peut être utilisé pour vérifier que le tableau a cette valeur.

Je pourrais même combiner ces deux avec $this->logicalAnd. Mais cela ne donne bien sûr pas le résultat souhaité.

Jusqu'à présent, j'ai utilisé returnCallback, capturé tous les $ params et ensuite faire des affirmations à ce sujet, mais y a-t-il peut-être une autre façon de faire ce que je veux?

37
Anti Veeranna

J'ai fini par créer ma propre classe de contraintes, basée sur l'attribut un

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

Il peut être utilisé comme ceci:

 ... ->with(new Test_Constraint_ArrayHas($this->equalTo($value), $key));
8
Anti Veeranna

La méthode $this->arrayHasKey('keyname'); existe mais son nom est assertArrayHasKey:

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

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

Au lieu de créer une classe de contrainte réutilisable, j'ai pu affirmer la valeur d'une clé de tableau en utilisant la contrainte de rappel existante dans PHPUnit. Dans mon cas d'utilisation, j'avais besoin de vérifier une valeur de tableau dans le deuxième argument d'une méthode simulée ( MongoCollection :: ensureIndex () , si quelqu'un est curieux). Voici ce que j'ai trouvé:

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

La contrainte de rappel attend un appelable dans son constructeur, et l'appelle simplement lors de l'évaluation. L'assertion réussit ou échoue selon que l'appelable retourne vrai ou faux.

Pour un grand projet, je recommanderais certainement de créer une contrainte réutilisable (comme dans la solution ci-dessus) ou de demander que PR # 312 soit fusionné dans PHPUnit, mais cela a fait l'affaire pour un. - besoin de temps. Il est facile de voir comment la contrainte de rappel peut également être utile pour des assertions plus complexes.

15
jmikola

Si vous souhaitez effectuer des tests complexes sur le paramètre, ainsi que des messages et des comparaisons utiles, il y a toujours la possibilité de placer des assertions dans le rappel.

par exemple.

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

Notez que le rappel retourne true. Sinon, cela échouerait toujours.

3
Dane Lowe