Искове
Твърденията се използват за потвърждаване, че действителната
стойност съответства на очакваната стойност. Това са методи
Tester\Assert
.
Изберете най-точните твърдения. По-добре Assert::same($a, $b)
,
отколкото Assert::true($a === $b)
, защото при неуспех извежда смислено
съобщение за грешка. Във втория случай получаваме само
false should be true
, а той не казва нищо за съдържанието на променливите
$a и $b.
Повечето оператори могат да имат и незадължителен $description
,
който се появява в съобщението за грешка, ако не успеят.
Примерите предполагат, че е дефиниран следният псевдоним на клас:
use Tester\Assert;
Assert::same ($expected, $actual, ?string $description=null)
$expected
трябва да бъде същото като $actual
. Това е същото като
оператора на PHP ===
.
Assert::notSame ($expected, $actual, ?string $description=null)
Противоположен на Assert::same()
, така че е същият като оператора на
PHP !==
.
Assert::equal ($expected, $actual, ?string $description=null, bool $matchOrder=false, bool $matchIdentity=false)
$expected
трябва да бъде същото като $actual
. За разлика от
Assert::same()
, идентичността на обектите, редът на двойките ключ ⇒
стойност в масивите и леко различаващите се десетични числа се
игнорират, което може да се промени чрез задаване на $matchIdentity
и
$matchOrder
.
Следните случаи са идентични за equal()
, но не и за same()
:
Assert::equal(0.3, 0.1 + 0.2);
Assert::equal($obj, clone $obj);
Assert::equal(
['first' => 11, 'second' => 22],
['second' => 22, 'first' => 11],
);
Предупреждаваме ви обаче, че масивът [1, 2]
и [2, 1]
не са
еднакви, тъй като се различава само редът на стойностите, а не двойките
ключ ⇒ стойност. Масивът [1, 2]
може да се запише и като
[0 => 1, 1 => 2]
и следователно [1 => 2, 0 => 1]
ще се считат
за равни.
Можете да използвате и т.нар. изчакване в
$expected
.
Assert::notEqual ($expected, $actual, ?string $description=null)
Контраст Assert::equal()
.
Assert::contains ($needle, string|array $actual, ?string $description=null)
Ако $actual
е низ, той трябва да съдържа подниз от $needle
. Ако
е масив, той трябва да съдържа елемент $needle
(сравнява се
стриктно).
Assert::notContains ($needle, string|array $actual, ?string $description=null)
Обратното на Assert::contains()
.
Assert::hasKey (string|int $needle, array $actual, ?string $description=null)
$actual
трябва да бъде масив и да съдържа ключа $needle
.
Assert::notHasKey (string|int $needle, array $actual, ?string $description=null)
$actual
трябва да бъде масив и да не съдържа ключа $needle
.
Assert::true ($value, ?string $description=null)
$value
трябва да бъде true
, така че $value === true
.
Assert::truthy ($value, ?string $description=null)
$value
трябва да е вярно, така че то отговаря на условието
if ($value) ...
.
Assert::false ($value, ?string $description=null)
$value
трябва да бъде false
, следователно $value === false
.
Assert::falsey ($value, ?string $description=null)
$value
трябва да е false, така че то отговаря на условието
if (!$value) ...
.
Assert::null ($value, ?string $description=null)
$value
трябва да бъде null
, така че $value === null
.
Assert::notNull ($value, ?string $description=null)
$value
не следва да бъде null
, следователно
$value !== null
.
Assert::nan ($value, ?string $description=null)
$value
трябва да бъде Не е число. Използвайте Assert::nan()
само
за тестване на NAN. Стойността на NAN е много специфична и изявленията
Assert::same()
или Assert::equal()
могат да се държат
непредсказуемо.
Assert::count ($count, Countable|array $value, ?string $description=null)
Броят на елементите в $value
трябва да е равен на $count
. Това
е същото като count($value) === $count
.
Assert::type (string|object $type, $value, ?string $description=null)
$value
трябва да е от посочения тип. Като $type
можем да
използваме символа:
array
list
е масив, индексиран във възходящ цифров ред на ключовете от нула.bool
callable
float
int
null
object
resource
scalar
string
- директно име на клас или обект, тогава трябва да
предадете
$value instanceof $type
Assert::exception (callable $callable, string $class, ?string $message=null, $code=null)
При извикване на $callable
трябва да се хвърли изключение за
$class
. Ако подадем $message
, съобщението за изключение трябва
да съвпадне. И ако подадем $code
, кодът на
изключението трябва да е същият.
Например този тест не успява, защото съобщението за изключение не съвпада:
Assert::exception(
fn() => throw new App\InvalidValueException('Нулевое значение'),
App\InvalidValueException::class,
'Значение слишком мало',
);
Assert::exception()
връща хвърлено изключение, за да можете да
проверите вложеното изключение.
$e = Assert::exception(
fn() => throw new MyException('Что-то не так', 0, new RuntimeException),
MyException::class,
'Something is wrong',
);
Assert::type(RuntimeException::class, $e->getPrevious());
Assert::error (string $callable, int|string|array $type, ?string $message=null)
Проверява дали извикването на $callable
генерира очакваните
грешки (т.е. предупреждения, известия и т.н.). Като $type
посочваме
една от константите E_...
, например E_WARNING
. А ако подадем
$message
, съобщението за грешка също трябва да съответства на шаблона. Например:
Assert::error(
fn() => $i++,
E_NOTICE,
'Undefined variable: i',
);
Ако обратното извикване генерира повече грешки, трябва да ги
очакваме в точен ред. В този случай предаваме масива на $type
:
Assert::error(function () {
$a++;
$b++;
}, [
[E_NOTICE, 'Undefined variable: a'],
[E_NOTICE, 'Undefined variable: b'],
]);
Ако $type
е име на клас, това изявление се държи по същия
начин като Assert::exception()
.
Assert::noError (callable $callable)
Проверява дали $callable
не изхвърля никакви
предупреждения/бележки/грешки или изключения на PHP. Това е полезно за
проверка на части от кода, в които няма други оператори.
Assert::match (string $pattern, $actual, ?string $description=null)
$actual
трябва да съвпада с $pattern
. Можем да използваме две
опции за шаблони: регулярни изрази или заместващи символи.
Ако подадем регулярен израз като $pattern
, трябва да използваме
~
or #
, за да го отделим. Други разделители не се поддържат.
Например тест, в който $var
трябва да съдържа само
шестнадесетични цифри:
Assert::match('#^[0-9a-f]$#i', $var);
Друга възможност е подобна на сравнението на низове, но можем да
използваме някои заместващи символи в $pattern
:
%a%
един или повече символи, с изключение на символите за край на реда%a?%
нула или повече символи, с изключение на символите за край на реда%A%
един или повече от всички символи, включително символите за край на реда%A?%
нула или повече символа, включително символите за край на реда%s%
един или повече интервали, с изключение на символите за край на реда%s?%
нула или повече интервали, с изключение на символите за край на реда%S%
един или повече знаци, с изключение на интервал%S?%
нула или повече знаци, с изключение на интервал%c%
една или повече цифри от всякакъв вид (с изключение на края на реда)%d%
една или повече цифри%d?%
нула или повече цифри%i%
подписана стойност в цяло число%f%
число с плаваща запетая%h%
една или повече цифри HEX%w%
един или повече буквено-цифрови знаци%%
един символ %
Примери:
# Again, hexadecimal number test
Assert::match('%h%', $var);
# Generalized path to file and line number
Assert::match('Error in file %a% on line %i%', $errorMessage);
Assert::matchFile (string $file, $actual, ?string $description=null)
Изпълнението е идентично с това на Assert::match(), но
шаблонът е зареден от $file
. Това е полезно за тестване на много
дълги низове. Тестовият файл става четим.
Assert::fail (string $message, $actual=null, $expected=null)
Това твърдение винаги е неуспешно. Това е просто удобно. Ако е необходимо, можем да предадем очаквани и действителни стойности.
Очаквания
Ако искаме да сравним по-сложни структури с непостоянни елементи,
горните твърдения може да не са достатъчни. Например, тестваме метод,
който създава нов потребител и връща атрибутите му като масив. Не знаем
хеш стойността на паролата, но знаем, че тя трябва да е шестнадесетичен
низ. А всичко, което знаем за следващия елемент, е, че той трябва да бъде
обектът DateTime
.
В тези случаи можем да използваме Tester\Expect
вътре в параметъра
$expected
методи Assert::equal()
и Assert::notEqual()
, с които лесно
можем да опишем структурата.
use Tester\Expect;
Assert::equal([
'id' => Expect::type('int'), # we expect an integer
'username' => 'milo',
'password' => Expect::match('%h%'), # we expect a string matching pattern
'created_at' => Expect::type(DateTime::class), # we expect an instance of the class
], User::create(123, 'milo', 'RandomPaSsWoRd'));
С Expect
можем да направим почти същите твърдения като с
Assert
. Така че имаме методи като Expect::same()
, Expect::match()
,
Expect::count()
и т.н. Освен това можем да ги обединим по
следния начин:
Expect::type(MyIterator::class)->andCount(5); # we expect MyIterator and items count is 5
Или можем да напишем свои собствени обработчици на изявления.
Expect::that(function ($value) {
# return false if expectation fails
});
Разследване на неуспешни твърдения
Tester показва къде се намира грешката, когато дадено твърдение не
успее. Когато сравняваме сложни структури, Tester създава дъмпове на
сравняваните стойности и ги записва в директорията output
.
Например, когато въображаемият тест Arrays.recursive.phpt
се провали,
изхвърлянията ще бъдат записани по следния начин:
app/
└── tests/
├── output/
│ ├──── Arrays.recursive.actual # фактическое значение
│ └──── Arrays.recursive.expected # ожидаемое значение
│
└── Arrays.recursive.phpt # неудачный тест
Можем да променим името на директорията на Tester\Dumper::$dumpDir
.