آشنایی با نحوهٔ توسعهٔ نرم‌افزار به سَبک TDD


پس از آنکه در ابتدای این فصل با مفهوم Test Driven Development یا به اختصار TDD آشنا شدیم، حال در این آموزش قصد داریم ببینیم که به چه شکل می‌توان از این پاراداریم در توسعهٔ نرم‌افزار استفاده نمود که این کار را با مد نظر قرار دادن مدلی تحت عنوان User انجام خواهیم داد که مرتبط با کلیهٔ تَسک‌های کاربران است.

پیش از این گفتیم که در روش TDD ابتدا به ساکن اقدام به نوشتن یک تست کرده که مسلماً پس از اجرا پاس نخواهد شد؛ سپس با توسعهٔ فانکشن اصلی کاری می‌کنیم تا تست مذکور پاس گردد. در همین راستا، داخل پوشهٔ tests یک فایل جدید با نامی دلخواه همچون UserTest.php ساخته و آن را به صورت زیر تکمیل می‌کنیم:

<?php
use PHPUnit\Framework\TestCase;

class UserTest extends TestCase
{
    public function testThatWeCanGetTheFirstName()
    {
        $user = new \App\Models\User;
        $user->setFirstName('Behzad');
        $this->assertEquals($user->getFirstName(), 'Behzad');
    }
}

ابتدا فرمان تست را اجرا کرده، خروجی را مشاهده می‌کنیم و سپس به تفسیر کدهای فوق خواهیم پرداخت:

/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

.E  2 / 2 (100%)

Time: 22 ms, Memory: 4.00 MB

There was 1 error:

1) UserTest::testThatWeCanGetTheFirstName
Error: Class 'App\Models\User' not found

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

ERRORS!
Tests: 2, Assertions: 1, Errors: 1.

همان‌طور که انتظار می‌رفت، این تست پاس نشد چرا که اساساً هیچ مدلی تحت عنوان User که در این تست مورد استفاده قرار داده‌ایم وجود خارجی ندارد به طوری که در متن ارور می‌بینیم:

1) UserTest::testThatWeCanGetTheFirstName
Error: Class 'App\Models\User' not found

تا این مرحله، طبق روالی که در TDD باید طی کرد،‌ نوشتن یک تستی که ابتدا به ساکن مردود می‌شود را با موفقیت انجام داده‌ایم. حال باید اقدام به توسعهٔ نرم‌افزار به گونه‌ای کنیم که این تست پاس گردد و همان‌طور که در ارور بالا مشاده می‌شود، گام اول ساخت کلاسی است که اصلاً وجود خارجی ندارد که در همین راستا، داخل پوشهٔ app ابتدا پوشه‌ای تحت عنوان Models ساخته سپس داخلش فایلی تحت عنوان User.php می‌سازیم:

<?php
namespace App\Models;

class User
{

}

در تفسیر کلاس فوق می‌توان گفت که در خط دوم ابتدا نِیم‌اِسپیس این فایل را مشخص کرده‌ایم تا اُتولودر پی‌اچ‌پی بتواند مسیر این فایل را بیابد سپس کلاسی خالی به نام User ساخته‌ایم. در این مرحله، نیاز است تا مجدد تست خود را ران کنیم به طوری که در خروجی خواهیم داشت:

/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

.E  2 / 2 (100%)

Time: 22 ms, Memory: 4.00 MB

There was 1 error:

1) UserTest::testThatWeCanGetTheFirstName
Error: Call to undefined method App\Models\User::setFirstName()

/var/www/phpunit/tests/UserTest.php:9

ERRORS!
Tests: 2, Assertions: 1, Errors: 1.

گرچه کماکان تست پاس نشده است، اما نوع ارور تغییر کرده‌ است به طوری می‌بینیم گفته شده متدی تحت عنوان ()setFirstName داخل کلاس User وجود ندارد که به منظور رفع این ارور، کلاس User را به صورت زیر تکمیل می‌کنیم:

<?php
namespace App\Models;

class User
{
    public $first_name;

    public function setFirstName($firstName)
    {
        $this->first_name = $firstName; 
    }
}

ابتدا یک پراپرتی تحت عنوان first_name$ تعریف کرده‌ایم که قرار است توسط متد ()setFirstName مقداردهی شود که در همین راستا پارامتری به نام firstName$ برای این متد در نظر گرفته‌ایم که مقدارش داخل بدنهٔ این متد به پراپرتی first_name$ اختصاص خواهد یافت. اکنون مجدد تست را ران می‌کنیم:

/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

.E  2 / 2 (100%)

Time: 24 ms, Memory: 4.00 MB

There was 1 error:

1) UserTest::testThatWeCanGetTheFirstName
Error: Call to undefined method App\Models\User::getFirstName()

/var/www/phpunit/tests/UserTest.php:10

ERRORS!
Tests: 2, Assertions: 1, Errors: 1.

می‌بینیم که تست پاس نشد اما باز هم نوع ارور آن تغییر کرد مبنی بر اینکه متدی تحت عنوان ()getFirstName داخل کلاس User وجود ندارد که برای رفع این ارور هم کلاس مذکور را به صورت زیر تکمیل می‌کنیم:

<?php
namespace App\Models;

class User
{
    public $first_name;

    public function setFirstName($firstName)
    {
        $this->first_name = $firstName;
    }

    public function getFirstName()
    {
        return $this->first_name;
    }
}

در واقع، متدی تحت عنوان ()getFirstName نوشته‌ایم که مقدار پراپرتی first_name$ که پیش از این توسط متد ()setFirstName مقداردهی شده بود را ریترن می‌کند. اکنون مجدد تست را ران می‌کنیم به طوری که در خروجی خواهیم داشت:

/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

..  2 / 2 (100%)

Time: 28 ms, Memory: 4.00 MB

OK (2 tests, 2 assertions)

می‌بینیم که تست با موفقیت پاس شد و این نوع کدنویسی و تکمیل پروژه همان توسعهٔ نرم‌افزار به روش Test Driven Development است.

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

در برنامه‌نویسی به روش TTD، همان‌طور که دیدیم، ابتدا ایدهٔ خود را در قالب یکسری تست پیاده‌سازی می‌کنیم که مسلماً هیچ‌کدام از آن‌ها پاس نخواهند شد. سپس برای آنکه کاری کنیم تا پاس شوند، اقدام به نوشتن اصطلاحاً Business Logic نرم‌افزار می‌کنیم و آن را آن‌قدر توسعه‌ داده، ریفتکور کرده و دیباگ می‌کنیم تا تست پاس گردد.



بهزاد مرادی

لیست نظرات
کاربر میهمان
دیدگاه شما چیست؟
کاربر میهمان