Pokud jde o automatizované testy nebo testy jednotek, v jakémkoli programovacím jazyce existují dva protichůdné názory:
Tímto článkem se tedy pokusíme přesvědčit prvně jmenované, zejména tím, že předvedeme, jak snadné je začít s automatizovaným testováním v Laravelu.
Nejprve si promluvme o „proč“ a poté se podívejme na několik příkladů jak.
Automatizované testy spouštějí části kódu a hlásí případné chyby. To je nejjednodušší způsob, jak je popsat. Představte si, že v aplikaci spustíte novou funkci a osobní robotický asistent by pak šel ručně otestovat novou funkci a zároveň by testoval, zda nový kód neporušil některou ze starých funkcí.
To je hlavní výhoda: automatické opětovné testování všech funkcí. Může se to zdát jako práce navíc, ale pokud neřeknete „robotovi“, aby to udělal, měli bychom to případně udělat ručně, že?
Nebo by mohly být nové funkce uvolněny bez testování, zda fungují, v naději, že uživatelé budou hlásit chyby.
Automatizované testy nám mohou poskytnout několik výhod:
Zkuste si představit vaši aplikaci za rok nebo dva, s novými vývojáři v týmu, kteří neznají kód napsaný v předchozích letech, ani neznají, jak jej testovat.
K provedení prvního automatizované testování v Laravelu, nemusíte psát žádný kód. Ano, čtete správně. Vše je již nakonfigurováno a připraveno v předinstalacidefinite of Laravel, včetně úplně prvního základního příkladu.
Můžete zkusit nainstalovat projekt Laravel a okamžitě spustit první testy:
laravel new project
cd project
php artisan test
Toto by měl být výsledek ve vaší konzoli:
Když se podíváme na předdefimísto Laravelu /tests
, máme dva soubory:
testy/Feature/ExampleTest.php :
class ExampleTest extends TestCase
{
public function test_the_application_returns_a_successful_response()
{
$response = $this->get('/');
$response->assertStatus(200);
}
}
Nepotřebujete znát žádnou syntaxi, abyste pochopili, co se zde děje: načtěte domovskou stránku a zkontrolujte, zda je stavový kód HTTP
è "200 OK
".
Také známý jako název metody test_the_application_returns_a_successful_response()
se stane čitelným textem, když si prohlížíte výsledky testu, jednoduše nahrazením symbolu podtržení mezerou.
testy/Unit/ExampleTest.php :
class ExampleTest extends TestCase
{
public function test_that_true_is_true()
{
$this->assertTrue(true);
}
}
Zdá se to trochu zbytečné, kontrolovat, zda je to pravda?
Konkrétně o jednotkových testech si povíme o něco později. Prozatím musíte pochopit, co se obecně děje v každém testu.
/tests
je třída PHP, která rozšiřuje TestCase of PHPUnitStrukturálně je to vše, co potřebujete vědět, vše ostatní závisí na konkrétních věcech, které chcete testovat.
Chcete-li vygenerovat prázdnou testovací třídu, jednoduše spusťte tento příkaz:
php artisan make:test HomepageTest
Soubor je vygenerován 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);
}
}
Nyní se podívejme, co se stane, když testovací tvrzení nevrátí očekávaný výsledek.
Změňme ukázkové testy na toto:
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);
}
}
A teď, když spustíme příkaz php artisan test
znovu:
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
Existují dva neúspěšné testy, označené jako NEÚSPĚŠNÉ, s vysvětlením níže a šipkami ukazujícími na přesnou řadu testů, které selhaly. Chyby jsou indikovány tímto způsobem.
Předpokládejme, že máme formulář a potřebujeme otestovat různé případy: zkontrolujeme, zda selže s neplatnými daty, zkontrolujeme, zda uspěje se správným zadáním atd.
Oficiální startovací sada od Laravel Breeze zahrnuje i testování funkčnosti v něm. Podívejme se na některé příklady odtud:
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);
}
}
Zde máme dva testy v jedné třídě, protože oba souvisejí s registračním formulářem: jeden kontroluje, zda je formulář správně načten, a druhý kontroluje, zda odeslání funguje dobře.
Pojďme se seznámit s dalšími dvěma způsoby ověření výsledku, dalšími dvěma tvrzeními: $this->assertAuthenticated()
e $response->assertRedirect()
. Všechna tvrzení dostupná v oficiální dokumentaci můžete zkontrolovat PHPUnit e Odpověď Laravel . Všimněte si, že na toto téma se vyskytují některá obecná tvrzení $this
, zatímco ostatní kontrolují konkrétní $response
z hovoru na trase.
Další důležitou věcí je use RefreshDatabase;
příkaz s tahem vloženým nad třídu. Je nezbytné, když testovací akce mohou ovlivnit databázi, jako v tomto příkladu, protokolování přidá novou položku do users
databázová tabulka. Za tímto účelem byste měli vytvořit samostatnou testovací databázi, která bude aktualizována php artisan migrate:fresh
pokaždé, když jsou testy spuštěny.
Máte dvě možnosti: fyzicky vytvořit samostatnou databázi nebo použít in-memory databázi SQLite. Obojí je nakonfigurováno v souboru phpunit.xml
ve výchozím nastavenídefinita s laravel. Konkrétně potřebujete tuto část:
<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>
Viz DB_CONNECTION
e DB_DATABASE
které jsou komentované? Pokud máte na svém serveru SQLite, nejjednodušší akcí je jednoduše odkomentovat tyto řádky a vaše testy poběží proti této databázi v paměti.
V tomto testu říkáme, že uživatel je úspěšně autentizován a přesměrován na správnou domovskou stránku, ale také můžeme otestovat aktuální data v databázi.
Kromě tohoto kódu:
$this->assertAuthenticated();
$response->assertRedirect(RouteServiceProvider::HOME);
Můžeme také použít databázová testovací tvrzení a udělejte něco takového:
$this->assertDatabaseCount('users', 1);
// Or...
$this->assertDatabaseHas('users', [
'email' => 'test@example.com',
]);
Podívejme se nyní na další příklad přihlašovací stránky s 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();
}
}
Jde o přihlašovací formulář. Logika je podobná registraci, že? Ale tři metody místo dvou, takže toto je příklad testování dobrých i špatných scénářů. Společnou logikou tedy je, že byste měli otestovat oba případy: když věci jdou dobře, i když selžou.
Také to, co vidíte v tomto testu, je použití Databázové továrny : Laravel vytváří falešného uživatele ( znovu ve vaší aktualizované testovací databázi ) a poté se pokusí přihlásit se správnými nebo nesprávnými přihlašovacími údaji.
Laravel opět generuje tovární predefinita s nepravdivými údaji pro User
model, mimo krabici.
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),
];
}
}
Vidíte, kolik věcí připravuje samotný Laravel, takže by pro nás bylo snadné začít s testováním?
Pokud tedy provedeme php artisan test
po instalaci Laravel Breeze bychom měli vidět něco takového:
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
Viděli jste podsložky tests/Feature
e tests/Unit
?.
Jaký je mezi nimi rozdíl?
Globálně, mimo ekosystém Laravel/PHP, existuje několik typů automatizovaného testování. Můžete najít výrazy jako:
Zní to složitě a skutečné rozdíly mezi těmito typy testů se někdy stírají. Laravel proto všechny tyto matoucí pojmy zjednodušil a seskupil je do dvou: jednotka/vlastnost.
Jednoduše řečeno, testy funkcí se snaží provést skutečnou funkčnost vašich aplikací: získat adresu URL, zavolat API, napodobit přesné chování, jako je vyplňování formuláře. Testy funkcí obvykle provádějí stejné nebo podobné operace, jaké by prováděl každý uživatel projektu ručně v reálném životě.
Jednotkové testy mají dva významy. Obecně můžete zjistit, že jakýkoli automatizovaný test se nazývá „testování jednotek“ a celý proces lze nazvat „testování jednotek“. Ale v kontextu funkčnosti versus jednotka je tento proces o testování konkrétní neveřejné jednotky kódu, izolovaně. Například máte třídu Laravel s metodou, která něco vypočítá, jako je celková cena objednávky s parametry. Test jednotky by tedy uvedl, zda jsou z této metody (kódové jednotky) vráceny správné výsledky s různými parametry.
Chcete-li vygenerovat test jednotky, musíte přidat příznak:
php artisan make:test OrderPriceTest --unit
Vygenerovaný kód je stejný jako test před jednotkoudefiLaravel systém:
class OrderPriceTest extends TestCase
{
public function test_example()
{
$this->assertTrue(true);
}
}
Jak vidíte, neexistuje RefreshDatabase
, a toto je jeden z definejběžnější definice unit testů: nedotýká se databáze, funguje jako „černá skříňka“, izolovaná od běžící aplikace.
Ve snaze napodobit příklad, který jsem zmínil dříve, si představme, že máme třídu služeb OrderPrice
.
app/Services/OrderPriceService.php:
class OrderPriceService
{
public function calculatePrice($productId, $quantity, $tax = 0.0)
{
// Some kind of calculation logic
}
}
Pak by test jednotky mohl vypadat nějak takto:
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
}
Podle mých osobních zkušeností s projekty Laravel jsou naprostá většina testů testy funkcí, nikoli testy jednotek. Nejprve musíte otestovat, zda vaše aplikace funguje, jak by ji používali skuteční lidé.
Dále, pokud máte speciální výpočty nebo logiku, můžete definire jako jednotku, s parametry, můžete vytvořit testy jednotek speciálně pro to.
Někdy psaní testů vyžaduje úpravu samotného kódu a jeho refaktorizaci, aby byl „testovatelnější“: rozdělení jednotek do speciálních tříd nebo metod.
Jaké je skutečné využití tohoto php artisan test
, kdy to máte spustit?
Existují různé přístupy v závislosti na vašem obchodním pracovním postupu, ale obecně se musíte ujistit, že všechny testy jsou „zelené“ (tj. bez chyb) před odesláním konečných změn kódu do úložiště.
Potom na svém úkolu pracujete lokálně, a když si myslíte, že jste hotovi, spusťte nějaké testy, abyste se ujistili, že jste nic neporušili. Pamatujte, že váš kód může způsobit chyby nejen ve vaší logice, ale také neúmyslně narušit některé jiné chování v kódu někoho jiného napsaného již dávno.
Pokud to uděláme o krok dále, je možné automatizovat mnoho věci. Pomocí různých nástrojů CI/CD můžete určit testy, které se mají spustit vždy, když někdo vloží změny do konkrétní větve Git nebo před sloučením kódu do produkční větve. Nejjednodušší pracovní postup by bylo použití Github Actions, mám samostatné video což dokazuje.
Existují různé názory na to, jak velké by mělo být takzvané „testovací pokrytí“: vyzkoušejte každou možnou operaci a případ na každé stránce nebo omezte práci na nejdůležitější části.
Ve skutečnosti zde souhlasím s lidmi, kteří obviňují automatizované testování z toho, že zabírá více času, než poskytuje skutečný přínos. To se může stát, pokud píšete testy pro každý jednotlivý detail. To znamená, že to může vyžadovat váš projekt: hlavní otázkou je „jaká je cena potenciální chyby“.
Jinými slovy, musíte upřednostnit své testovací úsilí položením otázky „Co by se stalo, kdyby tento kód selhal?“ Pokud má váš platební systém chyby, bude to mít přímý dopad na podnikání. Pokud je tedy funkčnost vašich rolí/oprávnění narušena, jedná se o velký bezpečnostní problém.
Líbí se mi, jak to řekl Matt Stauffer na konferenci: „Musíte nejprve otestovat ty věci, které, pokud selžou, vás vyhodí z práce.“ To je samozřejmě nadsázka, ale máte myšlenku: nejprve vyzkoušejte to důležité. A pak další funkce, pokud máte čas.
Všechny výše uvedené příklady jsou založeny na předběžném testovacím nástroji Laraveldefinoc: PHPUnit . Ale v průběhu let se v ekosystému objevily další nástroje a jedním z nejnovějších populárních je ŠKŮDCE . Vytvořeno oficiálním zaměstnancem Laravel Nuno Maduro , si klade za cíl zjednodušit syntaxi, čímž je psaní kódu pro testy ještě rychlejší.
Pod kapotou to běží su PHPUnit, jako další vrstva, se jen snaží minimalizovat některé předem opakované částidefičást kódu PHPUnit.
Podívejme se na příklad. Pamatujte na třídu předběžného testu funkcídefinited v Laravelu? Připomenu vám:
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);
}
}
Víte, jak by vypadal stejný test s PEST?
test('the application returns a successful response')->get('/')->assertStatus(200);
Ano, JEDEN řádek kódu a je to. Cílem PEST je tedy odstranit režii:
Chcete-li vygenerovat test PEST v Laravelu, musíte zadat další příznak:
php artisan make:test HomepageTest --pest
V době psaní tohoto článku je PEST mezi vývojáři Laravel docela populární, ale je to vaše osobní preference, zda použijete tento další nástroj a naučíte se jeho syntaxi, stejně jako poznámku PHPUnit.
BlogInnovazione.it
Námořní sektor je skutečnou globální ekonomickou velmocí, která se dostala na 150miliardový trh...
Minulé pondělí Financial Times oznámily dohodu s OpenAI. FT licencuje svou prvotřídní žurnalistiku…
Miliony lidí platí za streamovací služby a platí měsíční předplatné. Je obecný názor, že jste…
Společnost Coveware od společnosti Veeam bude i nadále poskytovat služby reakce na incidenty v oblasti kybernetického vydírání. Coveware nabídne forenzní a sanační schopnosti…