Nette Documentation Preview

syntax
Затвердження
************

.[perex]
Твердження використовуються для підтвердження того, що фактичне значення відповідає очікуваному значенню. Вони є методами `Tester\Assert`.

Виберіть найбільш точні твердження. Краще `Assert::same($a, $b)`, ніж `Assert::true($a === $b)`, тому що він виводить осмислене повідомлення про помилку при невдачі. У другому випадку ми отримуємо тільки `false should be true`, і воно нічого не говорить про вміст змінних $a і $b.

Більшість тверджень можуть також мати необов'язковий `$description`, який з'являється в повідомленні про помилку в разі невдачі.

Приклади припускають, що визначено наступний псевдонім класу:

```php
use Tester\Assert;
```


Assert::same($expected, $actual, ?string $description=null) .[method]
---------------------------------------------------------------------
`$expected` має бути те саме, що й `$actual`. Це те саме, що й оператор PHP `===`.


Assert::notSame($expected, $actual, ?string $description=null) .[method]
------------------------------------------------------------------------
Протилежний оператору `Assert::same()`, тому збігається з оператором PHP `!==`.


Assert::equal($expected, $actual, ?string $description=null, bool $matchOrder=false, bool $matchIdentity=false) .[method]
-------------------------------------------------------------------------------------------------------------------------
`$expected` має бути таким самим, як `$actual`. На відміну від `Assert::same()`, ідентичність об'єктів, порядок пар ключ => значення в масивах і незначно відмінні десяткові числа ігноруються, що можна змінити, задавши `$matchIdentity` і `$matchOrder`.

Наступні випадки ідентичні з точки зору `equal()`, але не для `same()`:

```php
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]` вважатиметься рівним.

Ви також можете використовувати так звані [очікування |#Expectations] в `$expected`.


Assert::notEqual($expected, $actual, ?string $description=null) .[method]
-------------------------------------------------------------------------
Протилежність `Assert::equal()`.


Assert::contains($needle, string|array $actual, ?string $description=null) .[method]
------------------------------------------------------------------------------------
Якщо `$actual` - рядок, то він повинен містити підрядок `$needle`. Якщо це масив, то він має містити елемент `$needle` (він порівнюється строго).


Assert::notContains($needle, string|array $actual, ?string $description=null) .[method]
---------------------------------------------------------------------------------------
Протилежність `Assert::contains()`.


Assert::hasKey(string|int $needle, array $actual, ?string $description=null) .[method]{data-version:2.4}
--------------------------------------------------------------------------------------------------------
`$actual` має бути масивом і містити ключ `$needle`.


Assert::notHasKey(string|int $needle, array $actual, ?string $description=null) .[method]{data-version:2.4}
-----------------------------------------------------------------------------------------------------------
`$actual` має бути масивом і не повинен містити ключ `$needle`.


Assert::true($value, ?string $description=null) .[method]
---------------------------------------------------------
`$value` має бути `true`, тому `$value === true`.


Assert::truthy($value, ?string $description=null) .[method]
-----------------------------------------------------------
`$value` має бути істинним, тому воно задовольняє умову `if ($value) ...`.


Assert::false($value, ?string $description=null) .[method]
----------------------------------------------------------
`$value` має бути `false`, тому `$value === false`.


Assert::falsey($value, ?string $description=null) .[method]
-----------------------------------------------------------
`$value` має бути хибним, тому він задовольняє умову `if (!$value) ...`.


Assert::null($value, ?string $description=null) .[method]
---------------------------------------------------------
`$value` має бути `null`, тому `$value === null`.


Assert::notNull($value, ?string $description=null) .[method]
------------------------------------------------------------
`$value` не повинно бути `null`, тому `$value !== null`.


Assert::nan($value, ?string $description=null) .[method]
--------------------------------------------------------
`$value` має бути Not a Number. Використовуйте тільки `Assert::nan()` для тестування NAN. Значення NAN дуже специфічне, і твердження `Assert::same()` або `Assert::equal()` можуть повести себе непередбачувано.


Assert::count($count, Countable|array $value, ?string $description=null) .[method]
----------------------------------------------------------------------------------
Кількість елементів у `$value` має дорівнювати `$count`. Тобто те саме, що й `count($value) === $count`.


Assert::type(string|object $type, $value, ?string $description=null) .[method]
------------------------------------------------------------------------------
`$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) .[method]
-------------------------------------------------------------------------------------------------
При виклику `$callable` має бути викинуто виключення екземпляра `$class`. Якщо ми передаємо `$message`, то повідомлення виключення має [збігатися |#Assert-match]. А якщо ми передаємо `$code`, то код виключення має бути таким самим.

Наприклад, цей тест не пройдено, тому що повідомлення виключення не збігається:

```php
Assert::exception(
	fn() => throw new App\InvalidValueException('Нулевое значение'),
	App\InvalidValueException::class,
	'Значение слишком мало',
);
```

Сайт `Assert::exception()` повертає кинуте виключення, тому ви можете перевірити вкладений виняток.

```php
$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) .[method]
----------------------------------------------------------------------------------------
Перевіряє, що виклик `$callable` генерує очікувані помилки (тобто попередження, повідомлення тощо). Як `$type` ми вказуємо одну з констант `E_...`, наприклад `E_WARNING`. І якщо передаємо `$message`, то повідомлення про помилку також має [відповідати |#Assert-match] шаблону. Наприклад:

```php
Assert::error(
	fn() => $i++,
	E_NOTICE,
	'Undefined variable: i',
);
```

Якщо зворотний виклик генерує більше помилок, ми повинні очікувати їх усі в точному порядку. У цьому випадку ми передаємо масив у `$type`:

```php
Assert::error(function () {
	$a++;
	$b++;
}, [
	[E_NOTICE, 'Undefined variable: a'],
	[E_NOTICE, 'Undefined variable: b'],
]);
```

.[note]
Якщо `$type` - ім'я класу, то це твердження поводиться так само, як і `Assert::exception()`.


Assert::noError(callable $callable) .[method]
---------------------------------------------
Перевіряє, що функція `$callable` не викидає жодних попереджень/зауважень/помилок або виключень PHP. Це корисно для перевірки частини коду, де немає інших тверджень.


Assert::match(string $pattern, $actual, ?string $description=null) .[method]
----------------------------------------------------------------------------
`$actual` повинен відповідати `$pattern`. Ми можемо використовувати два варіанти шаблонів: регулярні вирази або знаки підстановки.

Якщо ми передаємо регулярний вираз як `$pattern`, ми повинні використовувати `~` or `#` для його поділу. Інші роздільники не підтримуються. Наприклад, тест, де `$var` повинен містити тільки шістнадцяткові цифри:

```php
Assert::match('#^[0-9a-f]$#i', $var);
```

Інший варіант схожий на порівняння рядків, але ми можемо використовувати деякі дикі символи в `$pattern`:

- `%a%` один або більше будь-яких символів, крім символів кінця рядка
- `%a?%` нуль або більше з чого завгодно, крім символів кінця рядка
- `%A%` один або більше з усього, включаючи символи кінця рядка
- `%A?%` нуль або більше будь-яких символів, включаючи символи кінця рядка
- `%s%` один або більше символів пробілу, за винятком символів кінця рядка
- `%s?%` нуль або більше символів пробілу, за винятком символів кінця рядка
- `%S%` один або більше символів, за винятком пробілу
- `%S?%` нуль або більше символів, за винятком пробілу
- `%c%` один символ будь-якого виду (крім кінця рядка)
- `%d%` одна або кілька цифр
- `%d?%` нуль або більше цифр
- `%i%` знакове цілочисельне значення
- `%f%` число з плаваючою комою
- `%h%` одна або кілька HEX-цифр
- `%w%` один або кілька буквено-цифрових символів
- `%%` один символ %

Приклади:

```php
# 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) .[method]
-----------------------------------------------------------------------------
Твердження ідентичне [Assert::match() |#Assert-match], але шаблон завантажується з `$file`. Це корисно для тестування дуже довгих рядків. Тестовий файл стає читабельним.


Assert::fail(string $message, $actual=null, $expected=null) .[method]
---------------------------------------------------------------------
Це твердження завжди зазнає невдачі. Це просто зручно. За бажанням ми можемо передавати очікувані та фактичні значення.


Очікування .[#toc-expectations]
-------------------------------
Якщо ми хочемо порівняти більш складні структури з непостійними елементами, наведених вище тверджень може бути недостатньо. Наприклад, ми тестуємо метод, який створює нового користувача і повертає його атрибути у вигляді масиву. Ми не знаємо хеш-значення пароля, але знаємо, що він має бути шістнадцятковим рядком. А про наступний елемент ми знаємо тільки те, що це має бути об'єкт `DateTime`.

У цих випадках ми можемо використовувати `Tester\Expect` всередині параметра `$expected` методів `Assert::equal()` і `Assert::notEqual()`, за допомогою яких можна легко описати структуру.

```php
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()` тощо. Крім того, ми можемо з'єднати їх у ланцюжок таким чином:

```php
Expect::type(MyIterator::class)->andCount(5);  # we expect MyIterator and items count is 5
```

Або ми можемо написати власні обробники тверджень.

```php
Expect::that(function ($value) {
	# return false if expectation fails
});
```


Розслідування невдалих тверджень .[#toc-failed-assertions-investigation]
------------------------------------------------------------------------
Tester показує, де знаходиться помилка, коли твердження зазнає невдачі. Коли ми порівнюємо складні структури, Tester створює дампи порівнюваних значень і зберігає їх у директорії `output`. Наприклад, коли уявний тест `Arrays.recursive.phpt` зазнає невдачі, дампи будуть збережені таким чином:

```
app/
└── tests/
	├── output/
	│ ├──── Arrays.recursive.actual   # фактическое значение
	│ └──── Arrays.recursive.expected # ожидаемое значение
	│
	└── Arrays.recursive.phpt         # неудачный тест
```

Ми можемо змінити ім'я директорії на `Tester\Dumper::$dumpDir`.

Затвердження

Твердження використовуються для підтвердження того, що фактичне значення відповідає очікуваному значенню. Вони є методами 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 має бути хибним, тому він задовольняє умову 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 має бути Not a Number. Використовуйте тільки 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.