Очікування · Pest
Очікування (expectations) в Pest описують, яким має бути результат, тож відхилення від очікуваної поведінки видно одразу. Саме так у коді знаходять помилки й інші проблеми.
Очікування починається з передачі значення у функцію expect($value). Ця функція потрібна щоразу, коли ви перевіряєте якесь значення. Саму по собі expect() викликають рідко: зазвичай до неї додають метод-очікування, який щось стверджує про значення.
test('sum', function () {
$value = sum(1, 2);
expect($value)->toBe(3); // Перевіряємо, що значення дорівнює 3...
});
Як видно, expect дозволяє зчеплювати кілька очікувань для одного $value. Тобто в одному тесті можна зробити стільки перевірок, скільки потрібно, просто додаючи наступні очікування в ланцюжок.
expect($value)
->toBeInt()
->toBe(3);
Будь-яке очікування можна перевернути, поставивши перед ним модифікатор not.
expect($value)
->toBeInt()
->toBe(3)
->not->toBeString() // Не має бути рядком...
->not->toBe(4); // Не має дорівнювати 4...
API очікувань Pest дає широкий набір окремих очікувань для перевірки різних аспектів коду. Нижче наведено повний перелік доступних очікувань.
toBe()toBeArray()toBeBetween()toBeEmpty()toBeTrue()toBeTruthy()toBeFalse()toBeFalsy()toBeGreaterThan()toBeGreaterThanOrEqual()toBeLessThan()toBeLessThanOrEqual()toContain()toContainEqual()toContainOnlyInstancesOf()toHaveCount()toHaveProperty()toHaveProperties()toMatchArray()toMatchObject()toEqual()toEqualCanonicalizing()toEqualWithDelta()toBeIn()toBeInfinite()toBeInstanceOf()toBeBool()toBeCallable()toBeFile()toBeFloat()toBeInt()toBeIterable()toBeNumeric()toBeDigits()toBeObject()toBeResource()toBeScalar()toBeString()toBeJson()toBeNan()toBeNull()toHaveKey()toHaveKeys()toHaveLength()toBeReadableDirectory()toBeReadableFile()toBeWritableDirectory()toBeWritableFile()toStartWith()toThrow()toEndWith()toMatch()toMatchConstraint()toBeUppercase()toBeLowercase()toBeAlpha()toBeAlphaNumeric()toBeSnakeCase()toBeKebabCase()toBeCamelCase()toBeStudlyCase()toHaveSnakeCaseKeys()toHaveKebabCaseKeys()toHaveCamelCaseKeys()toHaveStudlyCaseKeys()toHaveSameSize()toBeUrl()toBeUuid()
Окрім окремих очікувань, API пропонує кілька модифікаторів, якими тести налаштовують під себе. Вони дають змогу будувати складніші очікування й перевіряти кілька значень за раз. Доступні модифікатори:
toBe()
Це очікування перевіряє, що $value і $expected мають однаковий тип і однакове значення.
З обʼєктами воно перевіряє, що обидві змінні вказують на той самий обʼєкт.
expect(1)->toBe(1);
expect('1')->not->toBe(1);
expect(new StdClass())->not->toBe(new StdClass());
toBeBetween()
Це очікування перевіряє, що $value міститься між двома значеннями. Працює з int,
float і DateTime.
expect(2)->toBeBetween(1, 3);
expect(1.5)->toBeBetween(1, 2);
$expectationDate = new DateTime('2023-09-22');
$oldestDate = new DateTime('2023-09-21');
$latestDate = new DateTime('2023-09-23');
expect($expectationDate)->toBeBetween($oldestDate, $latestDate);
toBeEmpty()
Це очікування перевіряє, що $value порожнє.
expect('')->toBeEmpty();
expect([])->toBeEmpty();
expect(null)->toBeEmpty();
toBeTrue()
Це очікування перевіряє, що $value дорівнює true.
expect($isPublished)->toBeTrue();
toBeTruthy()
Це очікування перевіряє, що $value є істинним за приведенням типів.
expect(1)->toBeTruthy();
expect('1')->toBeTruthy();
toBeFalse()
Це очікування перевіряє, що $value дорівнює false.
expect($isPublished)->toBeFalse();
toBeFalsy()
Це очікування перевіряє, що $value є хибним за приведенням типів.
expect(0)->toBeFalsy();
expect('')->toBeFalsy();
toBeGreaterThan($expected)
Це очікування перевіряє, що $value більше за $expected.
expect($count)->toBeGreaterThan(20);
toBeGreaterThanOrEqual($expected)
Це очікування перевіряє, що $value більше або дорівнює $expected.
expect($count)->toBeGreaterThanOrEqual(21);
toBeLessThan($expected)
Це очікування перевіряє, що $value менше за $expected.
expect($count)->toBeLessThan(3);
toBeLessThanOrEqual($expected)
Це очікування перевіряє, що $value менше або дорівнює $expected.
expect($count)->toBeLessThanOrEqual(2);
toContain($needles)
Це очікування перевіряє, що всі передані значення є елементами $value.
expect('Hello World')->toContain('Hello');
expect('Pest: an elegant PHP Testing Framework')->toContain('Pest', 'PHP', 'Framework');
expect([1, 2, 3, 4])->toContain(2, 4);
toContainEqual($needles)
Це очікування перевіряє, що всі передані значення є елементами $value з точністю до рівності значень.
expect([1, 2, 3])->toContainEqual('1');
expect([1, 2, 3])->toContainEqual('1', '2');
toContainOnlyInstancesOf($class)
Це очікування перевіряє, що $value містить лише екземпляри $class.
$dates = [new DateTime(), new DateTime()];
expect($dates)->toContainOnlyInstancesOf(DateTime::class);
toHaveCount(int $count)
Це очікування перевіряє, що переданий $count збігається з кількістю елементів в ітерованому $value.
expect(['Nuno', 'Luke', 'Alex', 'Dan'])->toHaveCount(4);
toHaveProperty(string $name, $value = null)
Це очікування перевіряє, що $value має властивість з іменем $name.
Другим аргументом можна перевірити ще й саме значення властивості.
expect($user)->toHaveProperty('name');
expect($user)->toHaveProperty('name', 'Nuno');
expect($user)->toHaveProperty('is_active', 'true');
toHaveProperties(iterable $name)
Це очікування перевіряє, що $value має властивості з усіма іменами, переліченими в $names.
expect($user)->toHaveProperties(['name', 'email']);
Асоціативним масивом можна перевірити імена і значення кількох властивостей одразу.
expect($user)->toHaveProperties([
'name' => 'Nuno',
'email' => 'enunomaduro@gmail.com'
]);
toMatchArray($array)
Це очікування перевіряє, що масив $value збігається з переданою підмножиною $array.
$user = [
'id' => 1,
'name' => 'Nuno',
'email' => 'enunomaduro@gmail.com',
'is_active' => true,
];
expect($user)->toMatchArray([
'email' => 'enunomaduro@gmail.com',
'name' => 'Nuno'
]);
toMatchObject($object)
Це очікування перевіряє, що обʼєкт $value збігається з підмножиною властивостей переданого $object.
$user = new stdClass();
$user->id = 1;
$user->email = 'enunomaduro@gmail.com';
$user->name = 'Nuno';
expect($user)->toMatchObject([
'email' => 'enunomaduro@gmail.com',
'name' => 'Nuno'
]);
toEqual($expected)
Це очікування перевіряє, що $value і $expected мають однакове значення.
expect($title)->toEqual('Hello World');
expect('1')->toEqual(1);
expect(new StdClass())->toEqual(new StdClass());
toEqualCanonicalizing($expected)
Це очікування перевіряє, що $value і $expected мають однакові значення незалежно від порядку елементів.
$usersAsc = ['Dan', 'Fabio', 'Nuno'];
$usersDesc = ['Nuno', 'Fabio', 'Dan'];
expect($usersAsc)->toEqualCanonicalizing($usersDesc);
expect($usersAsc)->not->toEqual($usersDesc);
toEqualWithDelta($expected, float $delta)
Це очікування перевіряє, що абсолютна різниця між $value і $expected менша за $delta.
expect($durationInMinutes)->toEqualWithDelta(10, 5); // тривалість 10 хвилин з допуском 5 хвилин
expect(14)->toEqualWithDelta(10, 5); // Проходить
expect(14)->toEqualWithDelta(10, 0.1); // Падає
toBeIn()
Це очікування перевіряє, що $value є одним із переданих значень.
expect($newUser->status)->toBeIn(['pending', 'new', 'active']);
toBeInfinite()
Це очікування перевіряє, що $value є нескінченністю.
expect(log(0))->toBeInfinite();
toBeInstanceOf($class)
Це очікування перевіряє, що $value є екземпляром $class.
expect($user)->toBeInstanceOf(User::class);
toBeArray()
Це очікування перевіряє, що $value є масивом.
expect(['Pest','PHP','Laravel'])->toBeArray();
toBeBool()
Це очікування перевіряє, що $value має тип bool.
expect($isActive)->toBeBool();
toBeCallable()
Це очікування перевіряє, що $value має тип callable.
$myFunction = function () {};
expect($myFunction)->toBeCallable();
toBeFile()
Це очікування перевіряє, що рядок $value вказує на наявний файл.
expect('/tmp/some-file.tmp')->toBeFile();
toBeFloat()
Це очікування перевіряє, що $value має тип float.
expect($height)->toBeFloat();
toBeInt()
Це очікування перевіряє, що $value має тип integer.
expect($count)->toBeInt();
toBeIterable()
Це очікування перевіряє, що $value має тип iterable.
expect($array)->toBeIterable();
toBeNumeric()
Це очікування перевіряє, що $value є числовим значенням.
expect($age)->toBeNumeric();
expect(10)->toBeNumeric();
expect('10')->toBeNumeric();
toBeDigits()
Це очікування перевіряє, що $value містить лише цифри.
expect($year)->toBeDigits();
expect(15)->toBeDigits();
expect('15')->toBeDigits();
expect(0.123)->not->toBeDigits();
expect('0.123')->not->toBeDigits();
toBeObject()
Це очікування перевіряє, що $value має тип object.
$object = new stdClass();
expect($object)->toBeObject();
toBeResource()
Це очікування перевіряє, що $value має тип resource.
$handle = fopen('php://memory', 'r+');
expect($handle)->toBeResource();
toBeScalar()
Це очікування перевіряє, що $value має скалярний тип.
expect('1')->toBeScalar();
expect(1)->toBeScalar();
expect(1.0)->toBeScalar();
expect(true)->toBeScalar();
expect([1, '1'])->not->toBeScalar();
toBeString()
Це очікування перевіряє, що $value має тип string.
expect($string)->toBeString();
toBeJson()
Це очікування перевіряє, що $value є JSON-рядком.
expect('{"hello":"world"}')->toBeJson();
toBeNan()
Це очікування перевіряє, що $value не є числом (NaN).
expect(sqrt(-1))->toBeNan();
toBeNull()
Це очікування перевіряє, що $value дорівнює null.
expect(null)->toBeNull();
toHaveKey(string $key)
Це очікування перевіряє, що $value містить переданий $key.
expect(['name' => 'Nuno', 'surname' => 'Maduro'])->toHaveKey('name');
expect(['name' => 'Nuno', 'surname' => 'Maduro'])->toHaveKey('name', 'Nuno');
expect(['user' => ['name' => 'Nuno', 'surname' => 'Maduro']])->toHaveKey('user.name');
expect(['user' => ['name' => 'Nuno', 'surname' => 'Maduro']])->toHaveKey('user.name', 'Nuno');
toHaveKeys(array $keys)
Це очікування перевіряє, що $value містить передані $keys.
expect(['id' => 1, 'name' => 'Nuno'])->toHaveKeys(['id', 'name']);
expect(['message' => ['from' => 'Nuno', 'to' => 'Luke'] ])->toHaveKeys(['message.from', 'message.to']);
toHaveLength(int $number)
Це очікування перевіряє, що переданий $number збігається з довжиною рядка $value або з кількістю елементів в ітерованому $value.
expect('Pest')->toHaveLength(4);
expect(['Nuno', 'Maduro'])->toHaveLength(2);
toBeDirectory()
Це очікування перевіряє, що рядок $value вказує на каталог.
expect('/tmp')->toBeDirectory();
toBeReadableDirectory()
Це очікування перевіряє, що рядок $value вказує на каталог і що цей каталог доступний для читання.
expect('/tmp')->toBeReadableDirectory();
toBeReadableFile()
Це очікування перевіряє, що рядок $value вказує на файл і що цей файл доступний для читання.
expect('/tmp/some-file.tmp')->toBeReadableFile();
toBeWritableDirectory()
Це очікування перевіряє, що рядок $value вказує на каталог і що в цей каталог можна писати.
expect('/tmp')->toBeWritableDirectory();
toBeWritableFile()
Це очікування перевіряє, що рядок $value вказує на файл і що в цей файл можна писати.
expect('/tmp/some-file.tmp')->toBeWritableFile();
toStartWith(string $expected)
Це очікування перевіряє, що $value починається з переданого рядка.
expect('Hello World')->toStartWith('Hello');
toThrow()
Це очікування перевіряє, що замикання кидає конкретний клас винятку, конкретне повідомлення винятку або і те, і те.
expect(fn() => throw new Exception('Something happened.'))->toThrow(Exception::class);
expect(fn() => throw new Exception('Something happened.'))->toThrow('Something happened.');
expect(fn() => throw new Exception('Something happened.'))->toThrow(Exception::class, 'Something happened.');
expect(fn() => throw new Exception('Something happened.'))->toThrow(new Exception('Something happened.'));
toMatch(string $expression)
Це очікування перевіряє, що $value відповідає регулярному виразу.
expect('Hello World')->toMatch('/^hello wo.*$/i');
toEndWith(string $expected)
Це очікування перевіряє, що $value закінчується переданим рядком.
expect('Hello World')->toEndWith('World');
toMatchConstraint(Constraint $constraint)
Це очікування перевіряє, що $value відповідає вказаному обмеженню (constraint) PHPUnit.
use PHPUnit\Framework\Constraint\IsTrue;
expect(true)->toMatchConstraint(new IsTrue());
toBeUppercase(string $expected)
Це очікування перевіряє, що $value записане у верхньому регістрі.
expect('PESTPHP')->toBeUppercase();
toBeLowercase(string $expected)
Це очікування перевіряє, що $value записане в нижньому регістрі.
expect('pestphp')->toBeLowercase();
toBeAlpha(string $expected)
Це очікування перевіряє, що $value містить лише літери.
expect('pestphp')->toBeAlpha();
toBeAlphaNumeric(string $expected)
Це очікування перевіряє, що $value містить лише літери й цифри.
expect('pestPHP123')->toBeAlphaNumeric();
toBeSnakeCase()
Це очікування перевіряє, що $value містить рядок у форматі snake_case.
expect('snake_case')->toBeSnakeCase();
toBeKebabCase()
Це очікування перевіряє, що $value містить рядок у форматі kebab-case.
expect('kebab-case')->toBeKebabCase();
toBeCamelCase()
Це очікування перевіряє, що $value містить рядок у форматі camelCase.
expect('camelCase')->toBeCamelCase();
toBeStudlyCase()
Це очікування перевіряє, що $value містить рядок у форматі StudlyCase.
expect('StudlyCase')->toBeStudlyCase();
toHaveSnakeCaseKeys()
Це очікування перевіряє, що $value містить масив із ключами у форматі snake_case.
expect(['snake_case' => 'abc123'])->toHaveSnakeCaseKeys();
toHaveKebabCaseKeys()
Це очікування перевіряє, що $value містить масив із ключами у форматі kebab-case.
expect(['kebab-case' => 'abc123'])->toHaveKebabCaseKeys();
toHaveCamelCaseKeys()
Це очікування перевіряє, що $value містить масив із ключами у форматі camelCase.
expect(['camelCase' => 'abc123'])->toHaveCamelCaseKeys();
toHaveStudlyCaseKeys()
Це очікування перевіряє, що $value містить масив із ключами у форматі StudlyCase.
expect(['StudlyCase' => 'abc123'])->toHaveStudlyCaseKeys();
toHaveSameSize()
Це очікування перевіряє, що розмір $value і переданої ітерованої структури однаковий.
expect(['foo', 'bar'])->toHaveSameSize(['baz', 'bazz']);
toBeUrl()
Це очікування перевіряє, що $value є URL.
expect('https://pestphp.com/')->toBeUrl();
toBeUuid()
Це очікування перевіряє, що $value є UUID.
expect('ca0a8228-cdf6-41db-b34b-c2f31485796c')->toBeUuid();
and($value)
Модифікатор and() дозволяє передати нове $value і зчепити кілька очікувань в одному тесті.
expect($id)->toBe(14)
->and($name)->toBe('Nuno');
dd()
Модифікатор dd()
Модифікатор dd() виводить поточне $value очікування й зупиняє виконання коду. Це зручно для налагодження: ви бачите стан $value в конкретній точці тесту.
expect(14)->dd(); // 14
expect([1, 2])->sequence(
fn ($number) => $number->toBe(1),
fn ($number) => $number->dd(), // 2
);
ddWhen($condition)
Модифікатор ddWhen() виводить поточне $value очікування й зупиняє виконання коду, коли передана $condition істинна.
expect([1, 2])->each(
fn ($number) => $number->ddWhen(fn (int $number) => $number === 2) // 2
);
ddUnless($condition)
Модифікатор ddUnless() виводить поточне $value очікування й зупиняє виконання коду, коли передана $condition хибна.
expect([1, 2])->each(
fn ($number) => $number->ddUnless(fn (int $number) => $number === 1) // 2
);
each()
Модифікатор each() створює очікування для кожного елемента переданої ітерованої структури: він проходить по ній і застосовує очікування до кожного елемента.
expect([1, 2, 3])->each->toBeInt();
expect([1, 2, 3])->each->not->toBeString();
expect([1, 2, 3])->each(fn ($number) => $number->toBeLessThan(4));
json()
Модифікатор json() декодує поточне $value очікування з JSON у масив.
expect('{"name":"Nuno","credit":1000.00}')
->json()
->toHaveCount(2)
->name->toBe('Nuno')
->credit->toBeFloat();
expect('not-a-json')->json(); // Падає
match()
Модифікатор match() виконує замикання, повʼязане з першим ключем масиву, який збігається зі значенням першого аргумента методу.
expect($user->miles)
->match($user->status, [
'new' => fn ($userMiles) => $userMiles->ToBe(0),
'gold' => fn ($userMiles) => $userMiles->toBeGreaterThan(500),
'platinum' => fn ($userMiles) => $userMiles->toBeGreaterThan(1000),
]);
Щоб перевірити, чи очікуване значення дорівнює значенню, повʼязаному з ключем-збігом, замість замикання можна одразу передати очікуване значення як значення масиву.
expect($user->default_language)
->match($user->country, [
'PT' => 'Português',
'US' => 'English',
'TR' => 'Türkçe',
]);
not
Модифікатор not інвертує наступне очікування.
expect(10)->not->toBeGreaterThan(100);
expect(true)->not->toBeFalse();
ray()
Модифікатор ray() дозволяє налагоджувати поточне $value через myray.app.
expect(14)->ray(); // 14
expect([1, 2])->sequence(
fn ($number) => $number->toBe(1),
fn ($number) => $number->ray(), // 2
);
sequence()
Модифікатор sequence() задає послідовний набір очікувань для однієї ітерованої структури.
expect([1, 2, 3])->sequence(
fn ($number) => $number->toBe(1),
fn ($number) => $number->toBe(2),
fn ($number) => $number->toBe(3),
);
sequence() працює й з асоціативними структурами. Кожне замикання в послідовності отримує два аргументи: перший - очікування для значення, другий - очікування для ключа.
expect(['hello' => 'world', 'foo' => 'bar', 'john' => 'doe'])->sequence(
fn ($value, $key) => $value->toEqual('world'),
fn ($value, $key) => $key->toEqual('foo'),
fn ($value, $key) => $value->toBeString(),
);
Модифікатором sequence() можна також перевірити, що кожне значення в ітерованій структурі збігається з набором очікуваних значень. Тоді очікувані значення передають у sequence() напряму, без замикань.
expect(['foo', 'bar', 'baz'])->sequence('foo', 'bar', 'baz');
when()
Модифікатор when() запускає переданий колбек, коли перший аргумент методу обчислюється в true.
expect($user)
->when($user->is_verified === true, fn ($user) => $user->daily_limit->toBeGreaterThan(10))
->email->not->toBeEmpty();
unless()
Модифікатор unless() запускає переданий колбек, коли перший аргумент методу обчислюється в false.
expect($user)
->unless($user->is_verified === true, fn ($user) => $user->daily_limit->toBe(10))
->email->not->toBeEmpty();
Тепер, коли ви знаєте, як писати очікування, наступний розділ документації, «Хуки», розповідає про корисні функції на кшталт «beforeEach» і «afterEach»: ними задають передумови тестів і прибирання після них: Хуки →
Перекладаємо з офіційної документації, розділ за розділом, і не ховаємо недоперекладене. Помітили неточність у терміні чи реченні: напишіть, виправимо.