Калі справа даходзіць да аўтаматызаваных тэстаў або модульных тэстаў, у любой мове праграмавання ёсць два супрацьлеглыя меркаванні:
Такім чынам, у гэтым артыкуле мы паспрабуем пераканаць першага, асабліва прадэманстраваўшы, як лёгка пачаць аўтаматызаванае тэсціраванне ў Laravel.
Спачатку давайце пагаворым пра тое, "чаму", а потым паглядзім некалькі прыкладаў таго, як.
Аўтаматызаваныя тэсты запускаюць часткі кода і паведамляюць аб любых памылках. Гэта самы просты спосаб іх апісаць. Уявіце сабе, што вы запускаеце новую функцыю ў дадатку, а потым персанальны памочнік-робат пойдзе і ўручную праверыць новую функцыю, адначасова правяраючы, ці не парушае новы код якую-небудзь са старых функцый.
Гэта галоўная перавага: аўтаматычнае паўторнае тэставанне ўсіх функцый. Гэта можа здацца дадатковай працай, але калі вы не загадаеце «робату» зрабіць гэта, мы павінны зрабіць гэта ўручную, так?
Або новыя функцыі могуць быць выпушчаны без праверкі іх працы, спадзеючыся, што карыстальнікі будуць паведамляць пра памылкі.
Аўтаматызаваныя тэсты могуць даць нам некалькі пераваг:
Паспрабуйце ўявіць сваю праграму праз год ці два з новымі распрацоўшчыкамі ў камандзе, якія не ведаюць кода, напісанага ў папярэднія гады, і нават таго, як яго тэставаць.
Каб выканаць першае аўтаматызаванае тэсціраванне ў Laravel, вам не трэба пісаць код. Так, вы правільна прачыталі. Усё ўжо настроена і падрыхтавана ў перадусталёўцыdefiканец Laravel, уключаючы самы першы асноўны прыклад.
Вы можаце паспрабаваць усталяваць праект Laravel і неадкладна запусціць першыя тэсты:
laravel new project
cd project
php artisan test
Гэта павінен быць вынік у вашай кансолі:
Калі мы паглядзім на прэdefiканец Laravel /tests
, у нас ёсць два файла:
тэсты/Feature/ExampleTest.php :
class ExampleTest extends TestCase
{
public function test_the_application_returns_a_successful_response()
{
$response = $this->get('/');
$response->assertStatus(200);
}
}
Вам не трэба ведаць сінтаксіс, каб зразумець, што тут адбываецца: загрузіце галоўную старонку і праверце, ці код стану HTTP
і "200 OK
».
Таксама вядомы як назва метаду test_the_application_returns_a_successful_response()
становіцца чытэльным тэкстам, калі вы праглядаеце вынікі тэсту, проста замяніўшы сімвал падкрэслівання прабелам.
тэсты/Unit/ExampleTest.php :
class ExampleTest extends TestCase
{
public function test_that_true_is_true()
{
$this->assertTrue(true);
}
}
Здаецца, бессэнсоўна правяраць, ці праўда гэта?
Пра модульныя тэсты мы пагаворым крыху пазней. На дадзены момант вам трэба зразумець, што звычайна адбываецца ў кожным тэсце.
/tests
гэта клас PHP, які пашырае TestCase PHPUnitСтруктурна гэта ўсё, што вам трэба ведаць, усё астатняе залежыць ад канкрэтных рэчаў, якія вы хочаце праверыць.
Каб стварыць пусты тэставы клас, проста выканайце наступную каманду:
php artisan make:test HomepageTest
Файл згенераваны tests/Feature/HomepageTest.php
:
class HomepageTest extends TestCase
{
// Replace this method with your own ones
public function test_example()
{
$response = $this->get('/');
$response->assertStatus(200);
}
}
Давайце цяпер паглядзім, што адбудзецца, калі тэставыя зацвярджэнні не вернуць чаканага выніку.
Давайце зменім прыклады тэстаў на гэта:
class ExampleTest extends TestCase
{
public function test_the_application_returns_a_successful_response()
{
$response = $this->get('/non-existing-url');
$response->assertStatus(200);
}
}
class ExampleTest extends TestCase
{
public function test_that_true_is_false()
{
$this->assertTrue(false);
}
}
А цяпер, калі мы запусцім каманду php artisan test
зноў:
FAIL Tests\Unit\ExampleTest
⨯ that true is true
FAIL Tests\Feature\ExampleTest
⨯ the application returns a successful response
---
• Tests\Unit\ExampleTest > that true is true
Failed asserting that false is true.
at tests/Unit/ExampleTest.php:16
12▕ * @return void
13▕ */
14▕ public function test_that_true_is_true()
15▕ {
➜ 16▕ $this->assertTrue(false);
17▕ }
18▕ }
19▕
• Tests\Feature\ExampleTest > the application returns a successful response
Expected response status code [200] but received 404.
Failed asserting that 200 is identical to 404.
at tests/Feature/ExampleTest.php:19
15▕ public function test_the_application_returns_a_successful_response()
16▕ {
17▕ $response = $this->get('/non-existing-url');
18▕
➜ 19▕ $response->assertStatus(200);
20▕ }
21▕ }
22▕
Tests: 2 failed
Time: 0.11s
Ёсць два няўдалыя тэсты, пазначаныя як НЯМАЛЬНА, з тлумачэннямі ніжэй і стрэлкамі, якія паказваюць на дакладны радок няўдалых тэстаў. Памылкі пазначаюцца такім чынам.
Выкажам здагадку, што ў нас ёсць форма, і нам трэба праверыць розныя выпадкі: мы правяраем, ці не атрымліваецца яна з няправільнымі дадзенымі, мы правяраем, ці атрымліваецца яна з правільным уводам і г.д.
Афіцыйны стартавы набор ад Laravel Breeze уключае я тэставанне яго функцыянальнасці. Давайце паглядзім некалькі прыкладаў адтуль:
tests/Feature/RegistrationTest.php
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class RegistrationTest extends TestCase
{
use RefreshDatabase;
public function test_registration_screen_can_be_rendered()
{
$response = $this->get('/register');
$response->assertStatus(200);
}
public function test_new_users_can_register()
{
$response = $this->post('/register', [
'name' => 'Test User',
'email' => 'test@example.com',
'password' => 'password',
'password_confirmation' => 'password',
]);
$this->assertAuthenticated();
$response->assertRedirect(RouteServiceProvider::HOME);
}
}
Тут у нас ёсць два тэсты ў адным класе, паколькі яны абодва звязаны з формай рэгістрацыі: адзін правярае, ці правільна загружана форма, а другі правярае, ці правільна працуе заяўка.
Азнаёмімся яшчэ з двума метадамі праверкі выніку, яшчэ двума сцвярджэннямі: $this->assertAuthenticated()
e $response->assertRedirect()
. Вы можаце праверыць усе сцвярджэнні, даступныя ў афіцыйнай дакументацыі PHPUnit e Адказ Laravel . Звярніце ўвагу, што на гэтую тэму сустракаюцца некаторыя агульныя сцвярджэнні $this
, а іншыя правяраюць канкрэтныя $response
з маршрутнага выкліку.
Іншая важная рэч - гэта use RefreshDatabase;
заява, з рыскай, устаўленай над класам. Гэта неабходна, калі тэставыя дзеянні могуць паўплываць на базу дадзеных, як у гэтым прыкладзе, вядзенне часопіса дадае новы запіс у users
табліца базы дадзеных. Для гэтага неабходна стварыць асобную тэставую базу дадзеных, якая будзе абнаўляцца php artisan migrate:fresh
кожны раз, калі запускаюцца тэсты.
У вас ёсць два варыянты: фізічна стварыць асобную базу дадзеных або выкарыстоўваць базу дадзеных SQLite ў памяці. Абодва настроены ў файле phpunit.xml
прадугледжана па змаўчанніdefiНіта с Laravel. У прыватнасці, вам патрэбна гэтая частка:
<php>
<env name="APP_ENV" value="testing"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_DRIVER" value="array"/>
<!-- <env name="DB_CONNECTION" value="sqlite"/> -->
<!-- <env name="DB_DATABASE" value=":memory:"/> -->
<env name="MAIL_MAILER" value="array"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="TELESCOPE_ENABLED" value="false"/>
</php>
Глядзіце DB_CONNECTION
e DB_DATABASE
якія з іх каментуюцца? Калі ў вас ёсць SQLite на вашым серверы, самае простае дзеянне - проста раскаментаваць гэтыя радкі, і вашыя тэсты будуць працаваць з гэтай базай дадзеных у памяці.
У гэтым тэсце мы кажам, што карыстальнік паспяхова аўтэнтыфікаваны і перанакіраваны на правільную хатнюю старонку, але мы таксама можам праверыць фактычныя даныя ў базе дадзеных.
У дадатак да гэтага кода:
$this->assertAuthenticated();
$response->assertRedirect(RouteServiceProvider::HOME);
Мы таксама можам выкарыстоўваць тэставыя зацвярджэння базы дадзеных і зрабіць нешта накшталт гэтага:
$this->assertDatabaseCount('users', 1);
// Or...
$this->assertDatabaseHas('users', [
'email' => 'test@example.com',
]);
Давайце зараз паглядзім іншы прыклад старонкі ўваходу ў Laravel Breeze
tests/Feature/AuthenticationTest.php:
class AuthenticationTest extends TestCase
{
use RefreshDatabase;
public function test_login_screen_can_be_rendered()
{
$response = $this->get('/login');
$response->assertStatus(200);
}
public function test_users_can_authenticate_using_the_login_screen()
{
$user = User::factory()->create();
$response = $this->post('/login', [
'email' => $user->email,
'password' => 'password',
]);
$this->assertAuthenticated();
$response->assertRedirect(RouteServiceProvider::HOME);
}
public function test_users_can_not_authenticate_with_invalid_password()
{
$user = User::factory()->create();
$this->post('/login', [
'email' => $user->email,
'password' => 'wrong-password',
]);
$this->assertGuest();
}
}
Гаворка ідзе пра форму ўваходу. Логіка падобная на рэгістрацыю, так? Але тры метады замест двух, таму гэта прыклад праверкі як добрых, так і дрэнных сцэнарыяў. Такім чынам, звычайная логіка заключаецца ў тым, што вы павінны праверыць абодва выпадкі: калі справы ідуць добра і калі не.
Акрамя таго, тое, што вы бачыце ў гэтым тэсце, - гэта выкарыстанне Фабрыкі баз дадзеных : Laravel стварае фальшывага карыстальніка ( зноў жа, у вашай абноўленай тэставай базе дадзеных ), а потым спрабуе ўвайсці з правільнымі або няправільнымі ўліковымі дадзенымі.
У чарговы раз Laravel стварае фабрычны папярэдні файлdefinita з ілжывымі дадзенымі для User
мадэль, нестандартна.
database/factories/UserFactory.php:
class UserFactory extends Factory
{
public function definition()
{
return [
'name' => $this->faker->name(),
'email' => $this->faker->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
];
}
}
Разумееце, колькі рэчаў падрыхтавана самім Laravel, ці лёгка нам было б пачаць тэсціраванне?
Такім чынам, калі мы выканаем php artisan test
пасля ўстаноўкі Laravel Breeze мы павінны ўбачыць нешта накшталт гэтага:
PASS Tests\Unit\ExampleTest
✓ that true is true
PASS Tests\Feature\Auth\AuthenticationTest
✓ login screen can be rendered
✓ users can authenticate using the login screen
✓ users can not authenticate with invalid password
PASS Tests\Feature\Auth\EmailVerificationTest
✓ email verification screen can be rendered
✓ email can be verified
✓ email is not verified with invalid hash
PASS Tests\Feature\Auth\PasswordConfirmationTest
✓ confirm password screen can be rendered
✓ password can be confirmed
✓ password is not confirmed with invalid password
PASS Tests\Feature\Auth\PasswordResetTest
✓ reset password link screen can be rendered
✓ reset password link can be requested
✓ reset password screen can be rendered
✓ password can be reset with valid token
PASS Tests\Feature\Auth\RegistrationTest
✓ registration screen can be rendered
✓ new users can register
PASS Tests\Feature\ExampleTest
✓ the application returns a successful response
Tests: 17 passed
Time: 0.61s
Вы бачылі падпапкі tests/Feature
e tests/Unit
?.
У чым розніца паміж імі?
Ва ўсім свеце, па-за экасістэмай Laravel/PHP, існуе некалькі тыпаў аўтаматызаванага тэсціравання. Вы можаце знайсці такія тэрміны, як:
Гэта гучыць складана, і рэальныя адрозненні паміж гэтымі тыпамі тэстаў часам размытыя. Вось чаму Laravel спрасціў усе гэтыя заблытаныя тэрміны і згрупаваў іх у два: адзінка/функцыя.
Прасцей кажучы, тэсты функцый спрабуюць выканаць фактычную функцыянальнасць вашых прыкладанняў: атрымаць URL, выклікаць API, імітаваць дакладныя паводзіны, напрыклад, запаўненне формы. Тэсты функцый звычайна выконваюць тыя ж або падобныя аперацыі, што і любы карыстальнік праекта ўручную ў рэальным жыцці.
Адзінкавыя тэсты маюць два значэнні. Увогуле, вы можаце выявіць, што любы аўтаматызаваны тэст называецца «модульным тэсціраваннем», а ўвесь працэс можна назваць «модульным тэсціраваннем». Але ў кантэксце функцыянальнасці супраць блока, гэты працэс звязаны з тэставаннем пэўнай непублічнай адзінкі кода ў ізаляцыі. Напрыклад, у вас ёсць клас Laravel з метадам, які нешта вылічае, напрыклад, агульную цану замовы з параметрамі. Такім чынам, модульны тэст будзе паказваць, ці правільныя вынікі вяртаюцца з гэтага метаду (кодавай адзінкі) з іншымі параметрамі.
Каб стварыць модульны тэст, вам трэба дадаць сцяг:
php artisan make:test OrderPriceTest --unit
Згенераваны код такі ж, як і перад модульным тэстамdefiСістэма Laravel:
class OrderPriceTest extends TestCase
{
public function test_example()
{
$this->assertTrue(true);
}
}
Як бачыце, яго не існуе RefreshDatabase
, і гэта адзін з defiнайбольш распаўсюджаныя азначэнні модульнага тэсту: ён не закранае базу дадзеных, ён працуе як «чорная скрыня», ізаляваная ад запушчанага прыкладання.
Спрабуючы пераймаць прыклад, які я згадваў раней, давайце ўявім, што ў нас ёсць клас абслугоўвання OrderPrice
.
app/Services/OrderPriceService.php:
class OrderPriceService
{
public function calculatePrice($productId, $quantity, $tax = 0.0)
{
// Some kind of calculation logic
}
}
Тады модульны тэст можа выглядаць прыкладна так:
class OrderPriceTest extends TestCase
{
public function test_single_product_no_taxes()
{
$product = Product::factory()->create(); // generate a fake product
$price = (new OrderPriceService())->calculatePrice($product->id, 1);
$this->assertEquals(1, $price);
}
public function test_single_product_with_taxes()
{
$price = (new OrderPriceService())->calculatePrice($product->id, 1, 20);
$this->assertEquals(1.2, $price);
}
// More cases with more parameters
}
З майго асабістага досведу працы з праектамі Laravel, пераважная большасць тэстаў - гэта тэсты функцый, а не модульныя тэсты. Па-першае, вам трэба праверыць, ці працуе ваша прыкладанне так, як ім карысталіся б рэальныя людзі.
Далей, калі ў вас ёсць спецыяльныя разлікі або логіка, вы можаце definire як адзінка, з параметрамі, вы можаце ствараць модульныя тэсты спецыяльна для гэтага.
Часам напісанне тэстаў патрабуе мадыфікацыі самога кода і яго рэфактарынгу, каб зрабіць яго больш «тэсціраваным»: раздзяленне адзінак на спецыяльныя класы або метады.
Якая сапраўдная карысць ад гэтага php artisan test
, калі вы павінны запусціць яго?
Існуюць розныя падыходы ў залежнасці ад працоўнага працэсу вашага бізнесу, але звычайна вам трэба пераканацца, што ўсе тэсты з'яўляюцца «эканомнымі» (г.зн. без памылак), перш чым адпраўляць канчатковыя змены кода ў рэпазітар.
Затым вы працуеце над сваёй задачай лакальна, і калі лічыце, што скончылі, запусціце некаторыя тэсты, каб пераканацца, што вы нічога не зламалі. Памятайце, што ваш код можа выклікаць памылкі не толькі ў вашай логіцы, але і ненаўмысна парушыць некаторыя іншыя паводзіны ў чужым кодзе, напісаным даўно.
Калі мы зробім крок наперад, гэта магчыма аўтаматызаваць многія рэчы. З дапамогай розных інструментаў CI/CD вы можаце вызначыць тэсты, якія будуць запускацца кожны раз, калі хтосьці ўносіць змены ў пэўную галінку Git або перад аб'яднаннем кода ў галіну вытворчасці. Самым простым працоўным працэсам было б выкарыстоўваць Github Actions, у мяне ёсць асобнае відэа што даказвае гэта.
Існуюць розныя меркаванні наконт таго, наколькі вялікім павінен быць так званы «тэставы ахоп»: паспрабаваць усе магчымыя аперацыі і выпадкі на кожнай старонцы або абмежаваць працу найбольш важнымі часткамі.
Фактычна, тут я згодны з людзьмі, якія абвінавачваюць аўтаматызаванае тэсціраванне ў тым, што яно займае больш часу, чым прыносіць рэальную карысць. Гэта можа адбыцца, калі вы пішаце тэсты для кожнай дэталі. Тым не менш, гэта можа спатрэбіцца вашаму праекту: галоўнае пытанне - "якая цана патэнцыйнай памылкі".
Іншымі словамі, вам трэба расставіць прыярытэты ў вашых намаганнях па тэсціраванні, задаючы пытанне: «Што будзе, калі гэты код не атрымаецца?» Калі ў вашай плацежнай сістэме ёсць памылкі, гэта непасрэдна паўплывае на бізнес. Такім чынам, калі функцыянальнасць вашых роляў/дазволаў парушана, гэта вялізная праблема бяспекі.
Мне падабаецца, як сказаў Мэт Стауфер на канферэнцыі: «Вы павінны спачатку праверыць тыя рэчы, якія, калі яны не атрымаюцца, прывядуць да звальнення з працы». Вядома, гэта перабольшанне, але вы зразумелі: спачатку паспрабуйце важныя рэчы. А потым іншыя функцыі, калі ў вас ёсць час.
Усе прыведзеныя вышэй прыклады заснаваны на інструменце папярэдняга тэставання Laraveldefiноч: PHPUnit . Але з гадамі ў экасістэме з'явіліся іншыя інструменты, і адзін з апошніх папулярных ШКОДНІК . Створана афіцыйным супрацоўнікам Laravel Нуну Мадура , накіраваны на спрашчэнне сінтаксісу, што робіць напісанне кода для тэстаў яшчэ больш хуткім.
Пад капотам ён працуе su PHPUnit, як дадатковы ўзровень, проста спрабуе мінімізаваць некаторыя папярэдне паўтораныя часткіdefiканец кода PHPUnit.
Давайце паглядзім на прыкладзе. Запомніце папярэдні клас тэсціравання функцыйdefiу Laravel? Нагадаю:
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class ExampleTest extends TestCase
{
public function test_the_application_returns_a_successful_response()
{
$response = $this->get('/');
$response->assertStatus(200);
}
}
Ці ведаеце вы, як будзе выглядаць той самы тэст з PEST?
test('the application returns a successful response')->get('/')->assertStatus(200);
Так, АДЗІН радок кода і ўсё. Такім чынам, мэта PEST - выдаліць накладныя выдаткі на:
Каб згенераваць PEST-тэст у Laravel, вам неабходна ўказаць дадатковы сцяг:
php artisan make:test HomepageTest --pest
На момант напісання гэтага артыкула PEST даволі папулярны сярод распрацоўшчыкаў Laravel, але карыстацца гэтым дадатковым інструментам і вывучаць яго сінтаксіс, а таксама заўвагу PHPUnit вырашаць вам асабіста.
BlogInnovazione.it
Google DeepMind прадстаўляе палепшаную версію сваёй мадэлі штучнага інтэлекту. Новая ўдасканаленая мадэль забяспечвае не толькі...
Laravel, вядомы сваім элегантным сінтаксісам і магутнымі функцыямі, таксама забяспечвае трывалую аснову для модульнай архітэктуры. Там…
Cisco і Splunk дапамагаюць кліентам паскорыць іх шлях да Аперацыйнага цэнтра бяспекі (SOC) будучыні з дапамогай…
Праграмы-вымагальнікі дамінавалі ў навінах апошнія два гады. Большасць людзей добра ведаюць, што напады...
У паліклініцы Катаніі праведзена аперацыя афтальмапластыкі з выкарыстаннем камерцыйнай праграмы прагляду Apple Vision Pro…
Развіццё дробнай маторыкі з дапамогай размалёўкі рыхтуе дзяцей да больш складаных навыкаў, такіх як пісьмо. Размаляваць…
Ваенна-марскі сектар - гэта сапраўдная глабальная эканамічная сіла, якая перайшла да 150-мільярднага рынку...
У мінулы панядзелак Financial Times абвясціла аб здзелцы з OpenAI. FT ліцэнзуе сваю журналістыку сусветнага ўзроўню...