• Час читання ~4 хв
  • 10.09.2022

BDD, або поведінкова розробка, є популярним підходом до тестування в багатьох організаціях і має перевірену історію об’єднання зусиль тестування між командами. Але залишається відкритим питання, як ми можемо досягти цього в Laravel без необхідності вивчати нову структуру для тестування чи новий синтаксис мови, такий як Gherkin.

Для компанії можливість визначати процеси у зрозумілий спосіб і бути представленими в наших наборах тестів є величезною перевагою. Подібно до того, як Domain Driven Design дозволяє нам створювати всюдисущу мову для нашого коду, BDD дозволить нам мати всюдисущу мову для нашого тестування.

Розгляньмо кілька прикладів. про те, як може виглядати тест BDD, а потім розберемо це. Уявімо, що у нас є веб-додаток із формою реєстрації. Коли цю форму буде заповнено, ми очікуємо, що користувач буде зареєстрований, і він має автоматично ввійти в систему. Давайте подивимося на це в типовому тесті функції:

it('allows a user to register for an account', function (string $email) {
	expect(
		User::query()->count(),
	)->toEqual(0);
 
	post(
		route('register'),
		['name' => 'test', 'email' => $email, 'password' => 'password']
	)->assertRedirect(route('dashboard'));
 
	expect(
		User::query()->count(),
	)->toEqual(1);
})->with('emails');

Це простий приклад того, що ви можете зробити з pestPHP, щоб перевірити цю кінцеву точку, яка повторює надсилання форми. Як бачите, як розробнику, це відносно легко зрозуміти, якщо ви звикли тестувати за допомогою pest. Однак ваш інженер із забезпечення якості зіткнеться з цим, оскільки вони не звикли до pestPHP і він не має зрозумілого їм синтаксису.

Як ми можемо змінити це на використовувати BDD і синтаксис, який може бути зрозумілий нашому інженеру з контролю якості та ширшій команді? На щастя, плагін pestPHP дозволить нам використовувати підхід «Given When Then», типовий для світу BDD. Це плагін Give when then, і з ним легко почати. Виконайте таку команду композитора, щоб установити цей плагін:

composer require milroyfraser/pest-plugin-gwt --dev

Звідси ми можемо почати писати певні тести для BDD. Наразі ми хочемо мати на увазі одну річ: чи хочемо ми замінити наші тести, чи ми хочемо, щоб BDD покращив наш поточний набір тестів? Я хотів би покращити свій існуючий набір тестів, щоб уникнути втрати цінних тестів.

Візьмемо приклад, з яким я нещодавно зіткнувся. Я не використовував жодного конкретного пакета авторизації для своєї програми Laravel. Натомість мені потрібно було створити спеціальний потік автентифікації за допомогою одноразового пароля. Моя реєстраційна форма є компонентом Livewire, який обробляє логіку за мене. Отже, давайте спочатку напишемо тест функції, щоб переконатися, що наш компонент працює.

it('will submit the form and create a new user', function (string $email) {
	Livewire::test(
		RegisterForm::class,
	)->set(
		'name', 'test',
	)->set(
		'email', $email,
	)->set(
		'password', 'password',
	)->call(
		'submit'
	)->assertHasNoErrors(
		['name', 'email', 'password']
	);
})->with('emails');

Ми перевіряємо, чи можемо заповнити та надіслати форму. Ми могли б додати наші очікування щодо цього, щоб переконатися, що користувача створено в базі даних, але ми можемо спростити наш тест функцій і перемістити частину цієї логіки до тесту інтеграції.

У нашому випадку, як і більшість мого коду, я виконую логіку в класах Action, тому перенесення цього має великий сенс. Зазвичай у мене є єдині класи дій для всіх операцій читання та запису, які мені потрібно виконати, щоб CLI, Web і API могли використовувати всю схожу логіку - єдина різниця полягає в тому, як це називається. У наведеному вище прикладі наш компонент Livewire викличе дію для створення користувача.

Тож тепер давайте подивимося, як виглядатиме бізнес-процес у Gherkin синтаксис:

Scenario: The Register Action is handled
	Given the RegisterAction is created
	When the handle method is called
	Then a new user will be created

Правда, ми могли б написати це в стандартному тесті, і це мало б сенс для нас як розробників, але один із принципів DDD, який я люблю, — це всюдисуща мова, яку ви створюєте — майже як мова бізнесу.

For our BDD tests, I will create an Integration directory under test, so that I have:
Unit: Test-Driven Development
Feature: Test-Driven Development
Integration: Behavioral Driven Development

У нашому каталозі Integrations ми зберігатимемо всі наші сценарії, створені як тести pestPHP за допомогою плагіна, який ми встановили.

scenario('The RegisterAction is handled')
	->given(fn () => new RegisterAction())
	->when(fn (RegisterAction $action) => $action->handle(
		name: 'test',
		email: '[email protected]',
		password: 'password',
	))->then(fn () => assertDatabaseHas('users', [
		'name' => 'test',
		'email' => '[email protected]',
	]));

Як ви бачите з наведеного вище коду, його легко зрозуміти. Він дуже схожий на те, що ми могли б очікувати в більшості наборів тестів BDD, але в структурі ми звикли. У багатьох випадках ми зазвичай можемо безпосередньо перекласти це на історію користувача.

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

Тепер давайте перенесемо це до синтаксису Gherkin:


Нарешті, перейдемо до pestPHP із плагіном, який ми тестуємо:

Scenario: A user can activate their account
	Given a new user
	When they activate their account
	Then an email is sent to confirm the activation.

Тож ви бачите, що цей спосіб тестування має переваги для ваш набір тестів і ваша команда. Я не кажу, що ви повинні завжди використовуйте цей підхід, але для тих критичних бізнес-процесів він дає змогу відобразити процес із мови, яку бізнес розуміє, на набір тестів, який ви розумієте безпосередньо.

scenario('A user can activate their account')
	->given(fn (): User => User::factory()->inactive()->create())
	->when(fn () => Bus::fake())
	->when(fn (User $user): User => $user->activate())
	->then(function (User $user) {
		Bus::assertDispatched(ActivateUser::class);
	});

Чи ви Знайшли ще якісь захоплюючі способи покращити свою стратегію тестування у своїх програмах? Поділіться з нами своїми думками в Twitter!

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

Про мене

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

Про автора CrazyBoy49z
WORK EXPERIENCE
Контакти
Ukraine, Lutsk
+380979856297