PHPUnit: проверка того, что массив имеет ключ с заданным значением
Учитывая следующий класс:
<?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->post()
, содержит ключ с именем "key1", который имеет значение "Значение 1"?
Я не хочу проверять весь массив - это всего лишь пример кода, в реальном коде переданный массив имеет намного больше значений, я хочу проверить только одну пару ключ/значение.
Существует $this->arrayHasKey('keyname')
, который я могу использовать для проверки наличия ключа.
Существует также $this->contains('Value 1')
, который может использоваться для проверки того, что массив имеет это значение.
Я мог бы даже объединить эти два с $this->logicalAnd
. Но это, конечно, не дает желаемого результата.
До сих пор я использовал returnCallback, захватывая целые $params, а затем делал утверждения по этому поводу, но есть ли другой способ сделать то, что я хочу?
Ответы
Ответ 1
В итоге я создал свой собственный класс ограничений, основанный на атрибуте
<?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));
Ответ 2
Существует метод $this->arrayHasKey('keyname');
, но его имя assertArrayHasKey
:
// In your PHPUnit test method
$hi = array(
'fr' => 'Bonjour',
'en' => 'Hello'
);
$this->assertArrayHasKey('en', $hi); // Succeeds
$this->assertArrayHasKey('de', $hi); // Fails
Ответ 3
Вместо создания повторно используемого класса ограничений я смог утвердить значение ключа массива, используя существующее ограничение обратного вызова в PHPUnit. В моем примере использования мне нужно было проверить значение массива во втором аргументе на издеваемом методе (MongoCollection:: secureIndex(), если кто-либо Любопытно). Вот что я придумал:
$mockedObject->expects($this->once())
->method('mockedMethod')
->with($this->anything(), $this->callback(function($o) {
return isset($o['timeout']) && $o['timeout'] === 10000;
}));
ограничение обратного вызова ожидает вызова в своем конструкторе и просто вызывает его во время оценки. Утверждение проходит или не выполняется на основе того, возвращает ли вызываемый true или false.
Для большого проекта я бы рекомендовал создать повторно используемое ограничение (как в приведенном выше решении) или ходатайство для PR # 312, чтобы быть объединенным в PHPUnit, но это сделало трюк для разовой необходимости. Легко понять, как ограничение обратного вызова может быть полезно и для более сложных утверждений.
Ответ 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
Извините, я не англоговорящий.
Я думаю, что вы можете проверить, существует ли ключ в массиве с функцией array_key_exists, и вы можете проверить, существует ли значение с array_search
Например:
function checkKeyAndValueExists($key,$value,$arr){
return array_key_exists($key, $arr) && array_search($value,$arr)!==false;
}
Используйте !==
, потому что array_search возвращает ключ этого значения, если он существует, и может быть 0.