آموزش استفاده از PHPUnit در Laravel (قدم دوم)

بدون دیدگاه

توابع assertEquals()  و assertNull()

assert (از این به بعد تابع می نامیم) assertEquals() دو مقدار را با هم مقایسه می کند تا ببیند مساوی هستند یا خیر. ما می خواهیم از این تابع برای چک کردن مقدار برگشتی از تابع takeOne() استفاده کنیم. با توجه به اینکه تابع takeOne() مقدار Null بر می گرداند اگر  متغیر box خالی باشد، می توانیم از تابع assertNull() هم برای چک کردنش استفاده کنیم.

بر خلاف  assertTrue()assertFalse(), و assertNull(), تابع assertEquals() دو پارامتر میگیرد. اولی مقداری که مورد انتظار است و دومی مقدار واقعی.

ما می توانیم این توابع را در کلاس مان به شکل زیر پیاده سازی کنیم:

<?php
use App\Box;

class BasicTest extends TestCase
{
public function testHasItemInBox()
{
$box = new Box(['cat', 'toy', 'torch']);

$this->assertTrue($box->has('toy'));
$this->assertFalse($box->has('ball'));
}

public function testTakeOneFromTheBox()
{
$box = new Box(['torch']);

$this->assertEquals('torch', $box->takeOne());

// Null, now the box is empty
$this->assertNull($box->takeOne());
}
}

حالا دستور phpunit را اجرا کنید و خروجی زیر را خواهید دید:

OK (3 tests, 6 assertions)

assertContains(), assertCount(), و assertEmpty()

در نهایت سه تابع داریم که می توانند با آرایه ها کار کنند و از آنها برای چک کردن مقدار برگشتی متد startsWith($item) در کلاس Box می توان استفاده کرد. تابع assertContains() چک می کند که مقدار داده شده در آرایه هست یا خیر. تابع assertCount() تعداد آیتم های داخل آرایه را با مقدار داده شده بررسی می کند و assertEmpty() خالی بودن آرایه را تعیین می کند.

با توابع بالا می توانیم تست زیر را ایجاد کنیم:

<?php
use App\Box;

class BasicTest extends TestCase
{
public function testHasItemInBox()
{
$box = new Box(['cat', 'toy', 'torch']);

$this->assertTrue($box->has('toy'));
$this->assertFalse($box->has('ball'));
}

public function testTakeOneFromTheBox()
{
$box = new Box(['torch']);

$this->assertEquals('torch', $box->takeOne());

// Null, now the box is empty
$this->assertNull($box->takeOne());
}

public function testStartsWithALetter()
{
$box = new Box(['toy', 'torch', 'ball', 'cat', 'tissue']);

$results = $box->startsWith('t');

$this->assertCount(3, $results);
$this->assertContains('toy', $results);
$this->assertContains('torch', $results);
$this->assertContains('tissue', $results);

// Empty array if passed even
$this->assertEmpty($box->startsWith('s'));
}
}

یکبار دیگر تست را ذخیره کرده و اجرا کنید تا نتیجه زیر را ببینید:

OK (4 tests, 9 assertions)

تبریک! شما کلاس Box را با استفاده از ۷ تابع(Assertion) ساده PHPUnit تست کردید.با استفاده با همین توابع ساده می توانید کارهای زیادی انجام دهید و توابع پیچیده تر را یاد بگیرید تا تست های پیچیده تری بنویسید.

برنامه تان را تست کنید

Unit Testing هر جز برنامه شما در شرایط بسیار مختلفی می تواند کار می کند و قطعا باید بخشی از فرایند توسعه شما باشد، با این حال این تمام تستی نیست که شما باید انجام دهید. هنگامی که شما در حال ایجاد یک نرم افزار پیچیده، شامل view ها ناوبری و فرم ها، و … هستید حتما می خواهید این اجزاء را نیز آزمایش کنید. این جایی است که Helper های لاراول کارها را به آسانی انجام می دهند تقریبا در حد همان تست هایی که قبلا نوشتیم.

در همین رابطه :   چگونه برای افزایش امنیت، ورود دو مرحله ای Google Authenticator را به Laravel اضافه کنیم؟

ما قبلا به فایل های پیش فرض داخل پوشه ./tests/ نگاهی انداختیم و از فایل ./tests/ExampleTest.php صرف نظر کردیم.حالا آن را باز کنید باید شبیه کد زیر باشد:

<?php
class ExampleTest extends TestCase
{
/**
* A basic functional test example.
*
* @return void
*/
public function testBasicExample()
{
$this->visit('/')
->see('Laravel');
}
}

همانطور که می بینید تست داخل آن بسیار ساده است.بدون هیچ دانش قبلی در مورد توابع کمک کننده (helper) می توانیم حدس بزنیم چه کاری انجام می شود:

  1. وقتی صفحه اصلی / را باز کردی
  2. باید حتما “Laravel” را ببینی!

اگر برنامه لاراول مان را اجرا کنید در صفحه اصلی آن می توانید عبارت “Laravel” را ببینید.پس این تست از نظر PHPUnit با موفقیت اجرا خواهد شد.

visit(), see(), و dontSee()

حالا می خواهیم تست خودمان را بنویسیم.

اول، فایل ./routes/web.php راویرایش کنید، تا یک روت جدید به آن اضافه کنیم.

<?php
Route::get('/', function () {
return view('welcome');
});

Route::get('/alpha', function () {
return view('alpha');
});

بعد، view مورد نیاز را در ./resources/views/alpha.blade.php بسازید و کدهای زیر را که شامل کلمه Alpha می شود، داخل آن کپی کنید:

<!DOCTYPE html>
<html>
<head>
<title>Alpha</title>
</head>
<body>
<p>This is the Alpha page.</p>
</body>
</html>

حالا صفحه جدید را در مرورگرتان باز کنید تا از درست بودن کار تا اینجا مطمئن شوید: http://localhost:8000/alpha

و باید پیام “This is the Alpha page.” را ببینید.

حالا که تمپلیت مورد نظر را داریم یک تست جدید ایجاد می کنیم. دستور زیر را اجرا کنید:

php artisan make:test AlphaTest

حالا می خواهیم در تست بررسی کنیم که کلمه “alpha” در صفحه باشد ولی کلمه “beta” نباشد. برای این کار از تابع dontSee() استفاده می کنیم که برعکس تابع see() کار می کند.

پس تست ساده ما شبیه این خواهد بود:

<?php
class AlphaTest extends TestCase
{
public function testDisplaysAlpha()
{
$this->visit('/alpha')
->see('Alpha')
->dontSee('Beta');
}
}

آن را ذخیره کنید و مثل قبل اجرا کنید. باید نتیجه درست باشد و پیام زیر را ببینید:

OK (5 tests, 12 assertions)

تست ها را اول بنویسید

یک مورد جالب در مورد تست ها این است که شما می توانید از نظریه Test Driven Development یا TDD استفاده کنید و تست های تان را اول بنویسید. یعنی اول تست ها را می نویسید و آنها را اجرا می کنید و می بینید که Fail می شوند . سپس کدهایتان را می نویسید جوری که تست ها را پاس کنند.بنابراین اجازه دهید همین کار را برای صفحه بعدی انجام دهیم.

در همین رابطه :   چک کردن وضعیت وجود یک Record جدول در Laravel

اول، با دستور زیر کلاس BetaTest را ایجاد کنید:

php artisan make:test BetaTest

بعد، کلاس فوق را تغییر دهید تا مسیر

/beta

را برای بودن کلمه “Beta” چک کند:

<?php
class BetaTest extends TestCase
{
public function testDisplaysBeta()
{
$this->visit('/beta')
->see('Beta')
->dontSee('Alpha');
}
}

حالا تست را اجرا کنید. نتیجه باید پیام خطایی ناخوشایند مثل این باشد:

> ./vendor/bin/phpunit
PHPUnit 4.8.19 by Sebastian Bergmann and contributors.

....F.

Time: 144 ms, Memory: 14.25Mb

There was 1 failure:

۱) BetaTest::testDisplaysBeta
A request to [http://localhost/beta] failed. Received status code [404].

...

FAILURES!
Tests: 6, Assertions: 13, Failures: 1.

همانطور که می بینید یک خطا برای نبود روت داریم.پس آن را ایجاد می کنیم.

اول، فایل ./routes/web.php را باز کرده و یک روت جدید به مسیر /beta به آن اضافه می کنیم:

<?php
Route::get('/', function () {
return view('welcome');
});

Route::get('/alpha', function () {
return view('alpha');
});

Route::get('/beta', function () {
return view('beta');
});

و بعد view مورد نیاز را در مسیر ./resources/views/beta.blade.php می سازیم:

<!DOCTYPE html>
<html>
<head>
<title>Beta</title>
</head>
<body>
<p>This is the Beta page.</p>
</body>
</html>

حالا یکبار دیگر PHPUnit را اجرا کنید و نتیجه باید دوباره سبز شود!

> ./vendor/bin/phpunit
PHPUnit 4.8.19 by Sebastian Bergmann and contributors.

......

Time: 142 ms, Memory: 14.00Mb

OK (6 tests, 15 assertions)

حالا ما اولین صفحه مان را با استفاده از متد Test Driven Development ساختیم.

click()  و seePageIs()

لاراول همچنین helper هایی برای کلیک کردن در تست، روی لینک های موجود درصفحه دارد و همچنین راهی برای اینکه ببینیم صفحه مقصد لینک کدام صفحه است.

فرض کنید می خواهیم با استفاده از دو متد فوق، لینک هایی بین صفحات beta و alpha اضافه کنیم.

اول، باید تست هایمان را بروز کنیم. کلاس تست AlphaTest را باز کنید تا متد جدید به آن اضافه کنیم برای کلیک روی لینکی که در صفحه alpha قرار دارد و به صفحه beta می رود.

در همین رابطه :   ریدایرکت کاربر بعد از ورود در Laravel

این تست شبیه کد زیر خواهد بود:

<?php
class AlphaTest extends TestCase
{
public function testDisplaysAlpha()
{
$this->visit('/alpha')
->see('Alpha')
->dontSee('Beta');
}

public function testClickNextForBeta()
{
$this->visit('/alpha')
->click('Next')
->seePageIs('/beta');
}
}

دقت کنید که ما محتوای هر دو صفحه را در متد جدید testClickNextForBeta() چک نمی کنیم. متدهای قبلی این کار را انجام می دهند، بنابراین برای ما فقط مهم این است که با کلیک روی لینک “Next” به صفحه /beta می رویم یا خیر.

حالا هم می توانید تست را اجرا کنید ولی خطا خواهد داد زیرا هنوز HTML را بروز نکرده ایم.

بعد، کلاس BetaTest را نیز مشابه کلاس alpha تغییر می دهیم:

<?php
class BetaTest extends TestCase
{
public function testDisplaysBeta()
{
$this->visit('/beta')
->see('Beta')
->dontSee('Alpha');
}

public function testClickNextForAlpha()
{
$this->visit('/beta')
->click('Previous')
->seePageIs('/alpha');
}
}

و نوبت بروز کردن HTML برای اضافه کردن لینک است.فایل ./resources/views/alpha.blade.php را باز کنید و طبق کد زیر آن را تغییر دهید:

<!DOCTYPE html>
<html>
<head>
<title>Alpha</title>
</head>
<body>
<p>This is the Alpha page.</p>
<p><a href="/beta">Next</a></p>
</body>
</html>

همینطور برای ./resources/views/beta.blade.php نیز:

<!DOCTYPE html>
<html>
<head>
<title>Beta</title>
</head>
<body>
<p>This is the Beta page.</p>
<p><a href="/alpha">Previous</a></p>
</body>
</html>

فایل ها را ذخیره کنید و تست را اجرا نمایید:

> ./vendor/bin/phpunit
PHPUnit 4.8.19 by Sebastian Bergmann and contributors.

F....F..

Time: 175 ms, Memory: 14.00Mb

There were 2 failures:

۱) AlphaTest::testDisplaysAlpha
Failed asserting that '<!DOCTYPE html>
<html>
<head>
<title>Alpha</title>
</head>
<body>
<p>This is the Alpha page.</p>
<p><a href="/beta">Next</a></p>
</body>
</html>
' does not match PCRE pattern "/Beta/i".

۲) BetaTest::testDisplaysBeta
Failed asserting that '<!DOCTYPE html>
<html>
<head>
<title>Beta</title>
</head>
<body>
<p>This is the Beta page.</p>
<p><a href="/alpha">Previous</a></p>
</body>
</html>
' does not match PCRE pattern "/Alpha/i".

FAILURES!
Tests: 8, Assertions: 23, Failures: 2.

خوب تست ما یه جورایی خطا داده است. اگر با دقت به کد HTML مان نگاه کنید می بینید که حالا کلمات beta و alpha را به ترتیب در صفحات /alpha و /beta داریم. این به این معنی است که باید کمی تست ها را تغییر دهیم تا در این موقعیت کاذب قرار نگیرند.

داخل هر کدام از کلاس های AlphaTest and BetaTest متدهایی که با testDisplays* شروع می شوند تغییر دهید تا این تداخل کلمات رفع شود.

بعد از این تغییر هر دو تست به این شکل خواهند بود:

تست ./tests/AlphaTest.php می شود:

<?php
class AlphaTest extends TestCase
{
public function testDisplaysAlpha()
{
$this->visit('/alpha')
->see('Alpha')
->dontSee('Beta page');
}

public function testClickNextForBeta()
{
$this->visit('/alpha')
->click('Next')
->seePageIs('/beta');
}
}

تست ./tests/BetaTest.php می شود:

<?php
class BetaTest extends TestCase
{
public function testDisplaysBeta()
{
$this->visit('/beta')
->see('Beta')
->dontSee('Alpha page');
}

public function testClickNextForAlpha()
{
$this->visit('/beta')
->click('Previous')
->seePageIs('/alpha');
}
}

حالا اگر تست ها را اجرا کنید همه چیز باید اوکی باشد. حالا ما صفحات جدیدمان و لینک های داخل شان را تست کردیم.

منبع

دسته بندی : Laravel

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *