سرفصل‌های آموزشی
آموزش Unit Test
نوشتن اولین یونیت تست با استفاده از PHPUnit

نوشتن اولین یونیت تست با استفاده از PHPUnit

در این آموزش قصد داریم تا یک تست فرضی نوشته و نحوهٔ Pass/Fail شدن آن را مورد بررسی قرار دهیم که در همین راستا داخل پوشهٔ tests فایلی با نامی دلخواه همچون TmpTest.php نوشته و کدهای زیر را داخل آن می‌نویسیم:

<?php

class TmpTest extends \PHPUnit\Framework\TestCase
{

}

در تفسیر کدهای فوق می‌توان گفت که کلاسی ساخته‌ایم تحت عنوان TmpTest که کلیهٔ خصوصیات خود را از کلاس TestCase فریمورک PHPUnit به ارث می‌برد. نیاز به توضیح نیست حالت دیگری که می‌توانیم به این کلاس دسترسی داشته باشیم به صورت زیر است:

<?php
use PHPUnit\Framework\TestCase;

class TmpTest extends TestCase
{

}

همان‌طور که می‌بینیم، در خط دوم با استفاده از کیورد use مسیر این کلاس را وارد فایل خود کرده و پس از کیورد extends صرفاً نام کلاس مذکور را نوشته‌ایم. به طور کلی، از این پس فایل autoload.php داخل پوشهٔ vendor به صورت خودکار این کلاس و سایر کلاس‌های مورد استفاده را به برنامه‌ ایمپورت خواهد کرد.

در این مرحله از کار برای آنکه ببینیم رفتار PHPUnit چگونه است، مجدد تست مد نظر را ران می‌‌کنیم به طوری که در خروجی خواهیم داشت:

/var/www/phpunit$ ./vendor/bin/phpunit
PHPUnit 8.1.4 by Sebastian Bergmann and contributors.

Runtime:       PHP 7.3.4-1+ubuntu18.04.1+deb.sury.org+3
Configuration: /var/www/phpunit/phpunit.xml

W  1 / 1 (100%)

Time: 21 ms, Memory: 4.00 MB

There was 1 warning:

1) Warning
No tests found in class "TmpTest".

WARNINGS!
Tests: 1, Assertions: 0, Warnings: 1.

همان‌طور که ملاحظه می‌شود، هشداری در معرض دیدمان قرار می‌گیرد با این مضمون که «هیچ‌‌گونه تستی داخل کلاس مذکور یافت نشد.» که برای رفع این هشدار، کدهای فوق را به صورت زیر تکمیل می‌کنیم:

<?php 
use PHPUnit\Framework\TestCase;

class TmpTest extends TestCase
{
    public function testTrueAssertsToTrue()
    {
        $this->assertTrue(true);
    }
}

ابتدا با اجرای مجدد تست، خروجی را ملاحظه کرده سپس به تفسیر کدهای فوق خواهیم پرداخت:

/var/www/phpunit$ ./vendor/bin/phpunit
PHPUnit 8.1.4 by Sebastian Bergmann and contributors.

Runtime:       PHP 7.3.4-1+ubuntu18.04.1+deb.sury.org+3
Configuration: /var/www/phpunit/phpunit.xml

.  1 / 1 (100%)

Time: 20 ms, Memory: 4.00 MB

OK (1 test, 1 assertion)

می‌بینیم که عبارت (OK (1 test, 1 assertion در خروجی چاپ شده است به این معنی که یک تست با موفقیت انجام شده است اما پیش از ادامهٔ آموزش نیاز است تا با مفهوم Assertion در یونیت تست بیشتر آشنا شویم که در ادامه این موضوع را مورد بررسی قرار خواهیم داد.

آشنایی با مفهوم Assertion

کلمهٔ Assertion از فعل Assert به معنی «اظهار کردن» یا «ادعا کردن» صحت چیزی گرفته شده است و این اصطلاح در یونیت تست بدان معنا است که وقتی یک تست انجام می‌شود، طی آن ما به عنوان دولوپر یکسری ادعاها می‌‌کنیم بدین صورت که مثلاً‌ یک تابع خاص باید خروجی true را ریترن کند و یا کد وضعیت اچ‌تی‌تی‌پی تابعی دیگر می‌باید معادل با ۲۰۰ باشد که چیزهایی از این دست اصطلاحاً Assertion گفته می‌شوند. به عبارتی، ما در تست خود ادعاهایی داریم که پس از ران کردن تست کلیهٔ آن‌ ادعاها می‌باید ثابت شوند.

حال با مد نظر قرار دادن این نکته، ابتدا به تفسیر فانکشن ()testTrueAssertsToTrue پرداخته سپس خواهیم دید که در این تست چه ادعاهایی کرده‌ایم. آنچه در ارتباط با توابعی که در یک کلاس تست می‌نویسیم حائز اهمیت است اینکه نام کلیهٔ توابع می‌باید با کلمهٔ test آغاز شود که فقط و فقط در این صورت است که فریمورک PHPUnit قادر به تشخیص تست‌ها می‌باشد.

با در نظر گرفتن این اصل، نامی دلخواه برای تنها تابع موجود تحت عنوان ()testTrueAssertsToTrue در نظر گرفته‌ایم که این تابع هیچ‌کار خاصی انجام نمی‌دهد جز اینکه در آن ادعا کرده‌ایم مقدار true برابر با true است!

()assertTrue یکی از متدهای تعبیه‌شده داخل کلاس TestCase است که این وظیفه را دارا است تا اگر هر چیزی که مقدارش true است را به عنوان آرگومان ورودی به آن پاس دهیم، مهرتأیید روی ادعا (Assertion) ما زده و خروجی OK را در اختیارمان قرار دهد که برای درک بهتر این موضوع، کدهای فوق را به صورت زیر تغییر داده و مجدد تست را اجرا می‌کنیم:

public function testTrueAssertsToTrue()
{
    $result = (1 === 1);
    $this->assertTrue($result);
}

در واقع، متغیری تعریف کرده‌ایم تحت عنوان result$ و مقدار آن را برابر با (1 === 1) قرار داده‌ایم بدان معنا که مقدار عدد ۱ را برابر با مقدار عدد ۱ قرار داده‌ایم که مسلماً چون این دو عدد با هم برابر هستند، نتیجهٔ آن همواره true خواهد بود؛ سپس این متغیر را به عنوان آرگومان تابع ()assertTrue در نظر گرفته‌ایم که با اجرای این تست خواهیم دید:

/var/www/phpunit$ ./vendor/bin/phpunit
PHPUnit 8.1.4 by Sebastian Bergmann and contributors.

Runtime:       PHP 7.3.4-1+ubuntu18.04.1+deb.sury.org+3
Configuration: /var/www/phpunit/phpunit.xml

.  1 / 1 (100%)

Time: 21 ms, Memory: 4.00 MB

OK (1 test, 1 assertion)

می‌بینیم که خروجی همچون گذشته OK است. آنچه در ارتباط با خروجی فوق باید مد نظر قرار دهیم، بخش زیر است:

.  1 / 1 (100%)

همان‌طور که می‌بینیم، یک نقطه قرار داده شده است و این نقطه حاکی از آن است که ما کلاً یک تست داریم و این در حالی است که اگر برای پروژهٔ خود ده تست نوشته باشیم، شاهد ده نقطهٔ پشت سر هم خواهیم بود.

اکنون در ادامه و به منظور درک ماهیت تابع ()assertTrue، کدهای فوق را به صورت زیر تغییر می‌دهیم:

public function testTrueAssertsToTrue()
{
    $this->assertTrue(false);
}

که پس از اجرای مجدد تست در خروجی خواهیم دید:

/var/www/phpunit$ ./vendor/bin/phpunit
PHPUnit 8.1.4 by Sebastian Bergmann and contributors.

Runtime:       PHP 7.3.4-1+ubuntu18.04.1+deb.sury.org+3
Configuration: /var/www/phpunit/phpunit.xml

F                                                                   1 / 1 (100%)

Time: 21 ms, Memory: 4.00 MB

There was 1 failure:

1) TmpTest::testTrueAssertsToTrue
Failed asserting that false is true.

/var/www/phpunit/tests/TmpTest.php:8

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

همان‌طور که ملاحظه می‌شود، .FAILURES! Tests: 1, Assertions: 1, Failures: 1 با رنگ قرمز در معرض دیدمان قرار گرفته است که در تفسیر اجرای فوق می‌توان گفت که ما با استفاده از متد ()assertTrue در صدد آن هستیم که ادعا کنیم مقدار false برابر با true است که مسلماً چنین چیزی امکان‌پذیر نمی‌باشد و از همین روی با گزاره‌ای همچون «.Failed asserting that false is true» مواجه می‌شویم حاکی از آنکه «در نظر گرفتن مقدار false برابر با true موفقیت‌آمیز نبوده است.» اما چنانچه بخواهیم این تست پاس گردد، می‌توانیم به صورت زیر از متد دیگری تحت عنوان ()assertFalse استفاده نماییم:

public function testTrueAssertsToTrue()
{
    $this->assertFalse(false);
}

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

/var/www/phpunit$ ./vendor/bin/phpunit
PHPUnit 8.1.4 by Sebastian Bergmann and contributors.

Runtime:       PHP 7.3.4-1+ubuntu18.04.1+deb.sury.org+3
Configuration: /var/www/phpunit/phpunit.xml

.  1 / 1 (100%)

Time: 20 ms, Memory: 4.00 MB

در واقع،‌ ما با استفاده از تابع ()assertFalse قصد داریم ادعا کنیم که پارامتر ورودی برابر با false است و از آنجا که مسلماً false برابر با false است، خروجی این تست OK خواهد بود.

online-support-icon