【问题标题】:PHPUnit: Verifying that array has a key with given valuePHPUnit:验证数组是否具有给定值的键
【发布时间】:2010-12-02 00:26:57
【问题描述】:

给定以下类:

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

还有这个测试用例:

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

如何验证$params(它是一个数组)并传递给$Other-&gt;post() 包含一个名为“key1”且值为“Value 1”的键?

我不想验证所有数组 - 这只是一个示例代码,在实际代码中,传递的数组有更多的值,我只想验证其中的一个键/值对。

我可以使用$this-&gt;arrayHasKey('keyname') 来验证密钥是否存在。

还有$this-&gt;contains('Value 1'),可以用来验证数组是否有这个值。

我什至可以将这两者与$this-&gt;logicalAnd 结合起来。但这当然不会产生预期的结果。

到目前为止,我一直在使用 returnCallback,捕获整个 $params,然后对其进行断言,但是也许还有另一种方法可以做我想做的事?

【问题讨论】:

  • $this->attribute(Constraint, value) 能够做我所追求的,但它不适用于数组。

标签: php phpunit


【解决方案1】:

$this-&gt;arrayHasKey('keyname'); 方法存在,但它的名称是 assertArrayHasKey

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

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

【讨论】:

【解决方案2】:

代替创建可重用的约束类,我能够使用 PHPUnit 中现有的回调约束来断言数组键的值。在我的用例中,我需要检查模拟方法的第二个参数中的数组值(MongoCollection::ensureIndex(),如果有人好奇的话)。这是我想出的:

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

callback constraint 期望在其构造函数中有一个可调用对象,并在评估期间简单地调用它。断言通过或失败取决于可调用对象返回 true 还是 false。

对于一个大型项目,我当然建议创建一个可重用的约束(如上面的解决方案)或请求将PR #312 合并到 PHPUnit 中,但这可以满足一次性需求。很容易看出回调约束对更复杂的断言也可能有用。

【讨论】:

  • 是否可以在callback 约束中放置assert*
【解决方案3】:

我最终基于属性 one 创建了自己的约束类

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

可以这样使用:

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

【讨论】:

【解决方案4】:

如果您希望对参数进行一些复杂的测试,并且还有有用的消息和比较,则始终可以选择在回调中放置断言。

例如

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

请注意,回调返回 true。否则,它总是会失败。

【讨论】:

    【解决方案5】:

    如果您不介意在密钥不存在时出现错误(而不是失败),那么您可以使用以下方法。

    $this->assertEquals('Value 1', $params['key1']);
    

    【讨论】:

      【解决方案6】:

      对不起,我不会说英语。

      我觉得可以用array_key_exists函数测试一个key是否存在于数组中,用array_search可以测试这个值是否存在

      例如:

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

      使用!==,因为如果存在,array_search 返回该值的键并且可能为 0。

      【讨论】:

      • 这些我都知道,但我想在 PHPUnit 中设置一个断言。
      猜你喜欢
      • 2022-01-22
      • 2023-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-24
      相关资源
      最近更新 更多