حفظ استانداردها در یک پایگاه کد در حال رشد که چندین توسعه دهنده در آن مشارکت دارند می تواند دشوار و خسته کننده باشد. اطمینان از اینکه پایگاه کد از بهترین شیوه ها پیروی می کند و از استانداردها منحرف نمی شود برای هر پروژه ضروری است. اما این معمولاً چیزی است که فقط به صورت دستی با بررسی کد و سایر فرآیندهای مشابه قابل اجرا است. مانند هر کار دستی دیگری، این کار می تواند زمان بر، خسته کننده و مستعد خطا باشد. اینجاست که معماری تست مطرح می شود.
معماری تست به شما امکان می دهد استانداردهای کد مانند قراردادهای نامگذاری، استفاده از متد، ساختار دایرکتوری و غیره را به طور خودکار اعمال کنید.
در این مقاله قصد داریم با معماری تست و مزایای استفاده از آن آشنا شویم. سپس به نحوه نوشتن تستهای معماری برای برنامههای لاراول خود با استفاده از چارچوب تست محبوب PHP، Pest میپردازیم. در پایان، مطمئن خواهید بود که شروع به نوشتن تست های معماری برای برنامه های لاراول خود خواهید کرد. ما درمقاله آشنایی با تست نویسی با PEST به صورت مقدماتی به آن پرداخته ایم.
Pest چیست؟
Pest یک چارچوب تست PHP منبع باز است که بر روی PHPUnit ساخته شده است. در زمان نگارش، بیش از 9.4 میلیون بارگیری و 7.9 هزار ستاره در GitHub دارد. از یک سینتکس و رویکردی مشابه Jest (یک چارچوب تست محبوب جاوا اسکریپت) و RSpec Ruby استفاده می کند. اگر با نوشتن تست های جاوا اسکریپت با استفاده از Jest آشنا هستید، باید با استفاده از Pest برای تست های PHP احساس راحتی کنید.
برای مثال، تصور کنید یک تابع add
ساده دارید که دو عدد را با هم جمع میکند و میخواهید مطمئن شوید که مقدار صحیح را برمیگرداند. می توانید یک تست در Pest مانند این بنویسید:
test('add function returns the correct value')
->expect(add(1, 2))
->toBe(3);
همانطور که می بینیم، تست ها از یک سینتکس روان استفاده می کنند که به ما اجازه می دهد تا متد ها را با هم زنجیره کنیم. این منجر به تست هایی می شود که ساده، خواندن و درک آسان هستند.
مزیت استفاده از Pest برای تست برنامه های لاراول این است که چندین ویژگی را ارائه می دهد که می توانید از آنها برای بهبود تجربه تست خود استفاده کنید. این شامل:
تست معماری - این به شما امکان می دهد استانداردهای کد را به طور خودکار اعمال کنید، مانند قراردادهای نامگذاری، استفاده از متد، و ساختار دایرکتوری. (این چیزی است که در این مقاله به آن می پردازیم.)
تست موازی - این به شما امکان می دهد تست های خود را به صورت موازی اجرا کنید، که می تواند به افزایش سرعت مجموعه تست شما کمک کند.
تست لحظه ای - این به شما امکان می دهد تست کنید که مقادیر مشابه زمانی است که عکس فوری ایجاد شده است. تست عکس لحظه ای می تواند هنگام تست پاسخ های API یا هنگام انجام بازسازهای بزرگ کمک کند، و می خواهید مطمئن شوید که خروجی تغییر نکرده است.
پروفایل تست - این به شما امکان می دهد مدت زمان اجرای هر تست را مشاهده کنید و می تواند برای شناسایی تست های کندی که ممکن است بخواهید مجدداً انجام دهید مفید باشد.
حالت تماشا - این به شما امکان می دهد هر زمان که فایلی در پروژه شما تغییر می کند، تست خود را به طور خودکار دوباره اجرا کنید.
پوشش کد - این به شما امکان می دهد تا ببینید چه مقدار از کد شما توسط تست های شما اعمال می شود تا بدانید کدام بخش از پایگاه کد شما به تست های بیشتری نیاز دارد. همچنین میتواند بینشی در مورد پوشش نوع پایگاه کد شما برای شناسایی متدهایی که از انواع برگشتی و نکات نوع استفاده نمیکنند، ارائه دهد.
از آنجایی که Pest بر روی PHPUnit ساخته شده است، می توانید تست های PHPUnit موجود خود را نیز با استفاده از Pest اجرا کنید. این بدان معناست که برای اینکه بتوانید از آن استفاده کنید و از سایر ویژگیهایی که ارائه میدهد بهرهمند شوید، لازم نیست نگران انتقال تست های فعلی خود به Pest باشید. در لاراول 11 نیز PEST به صورت پیش فرض قرار دارد.
تست معماری چیست؟
تست معماری با تست های سنتی که معمولا برای پروژه های خود می نویسید متفاوت است. در حالی که تست های سنتی شما عملکرد برنامه شما را تست می کنند، تست های معماری ساختار برنامه شما را تست می کنند. آنها به شما اجازه می دهند استانداردها و سازگاری را در پروژه های خود اعمال کنید.
بسته به نوع پروژه ای که روی آن کار می کنید، ممکن است مجموعه ای از استانداردها یا دستورالعمل های تعیین شده توسط کارفرما، مشتری یا خودتان داشته باشید. برای مثال، ممکن است بخواهید مواردی مانند:
چک کردن دقیق نوع در همه فایل ها استفاده می شود.
دایرکتوری
app/Interfaces
فقط شامل Interfaces است.همه کلاسها در
app/Services
با سرویس پسوند میشوند (به عنوان مثال،UserService
،BillingService
، و غیره).همه مدلهای موجود در
app/Models
، کلاسIlluminate\Database\Eloquent\Model
را extend می کند.تمام کلاسهای عمل در
app/Actions
قابل فراخوانی هستند (به این معنی که دارای متدinvoke__
هستند).کنترلرها به جز فایلهای مسیرها در برنامه در جایی استفاده نمیشوند.
فقط traits در دایرکتوری
app/Traits
وجود دارد.همه کلاسهای داخل فهرست
app/DataTransferObjects
فقط خواندنی هستند.
به طور کلی، شما باید این موارد را به صورت دستی از طریق بررسی کد و سایر فرآیندهای مشابه اعمال کنید. با تست معماری، میتوانید این استانداردها را بهطور خودکار اجرا کنید و مطمئن باشید که از آنها پیروی میشوند. برای آشنایی با روش ها و نکات تست نویسی می توانید این مقاله را بررسی کنید.
به عنوان مثال، این تست ساده را انجام دهید که باعث می شود همه رابط ها در نیم اسپیس App\Interfaces
وجود داشته باشند:
test('interfaces namespace only contains interfaces')
->expect('App\Interfaces')
->toBeInterfaces();
تست فوق را می توان مانند هر تست PEST دیگر اجرا کرد. در صورتی که تمام فایلهای موجود در نیم اسپیس App\Interfaces
رابط باشند، تست انجام میشود. با این حال، اگر هر یک از فایلهای این نیم اسپیس رابط نباشند، تست با شکست مواجه میشود.
مزایای تست معماری
اکنون که درک اولیه ای از تست معماری داریم، بیایید به مزایای آن در پروژه های شما نگاه کنیم.
زمان بازبینی کد را کاهش دهید
همانطور که قبلاً اشاره کردیم، تست معماری یک متد عالی برای خودکار کردن فرآیند اجرای استانداردها در پایگاه کد شما است.
برای نشان دادن این موضوع، اجازه دهید به یک نمونه گردش کار بین دو توسعهدهنده در تیمی که از تست معماری استفاده نمیکنند، نگاه کنیم. ما فرض می کنیم که یکی از توسعه دهندگان روی یک ویژگی جدید کار می کند و در حال ارائه یک درخواست PR برای ادغام تغییرات خود در شاخه اصلی است:
توسعه دهنده A کد این ویژگی را می نویسد.
توسعه دهنده A یک درخواست PR ارائه می کند.
برنامه نویس A از توسعه دهنده B درخواست بررسی می کند.
توسعهدهنده B کد را بررسی میکند و یک مشکل معماری (مثلاً یک فایل در دایرکتوری اشتباه) را تشخیص میدهد.
برنامه نویس B در مورد درخواست PR نظر می گذارد و از برنامه نویس A می خواهد که مشکل را برطرف کند.
برنامه نویس A مشکل را برطرف می کند و درخواست بررسی دیگری می کند.
برنامه نویس B دوباره کد را بررسی می کند و درخواست PR را تایید می کند (با فرض اینکه خطای دیگری وجود نداشته باشد).
همانطور که می بینیم، این روند دارای پتانسیل کند شدن است زیرا به توسعه دهندگان دیگر در تیم متکی است. همچنین به توسعهدهنده دیگر بستگی دارد که این مشکل را تشخیص دهد، به این معنی که حتی اگر یک مشکل معماری وجود داشته باشد، همچنان میتواند مراحل تأیید را طی کند.
با استفاده از یک استراتژی تست معماری خودکار، فرآیند می تواند به شکل زیر باشد:
توسعه دهنده A کد این ویژگی را می نویسد.
(اختیاری) توسعه دهنده A تست های معماری را به صورت محلی اجرا می کند. اگر مشکلی را تشخیص دهند، آن را برطرف می کنند.
توسعه دهنده A یک درخواست PR ارائه می کند.
خط لوله CI تست های معماری را اجرا می کند.
توسعه دهنده هر گونه مشکل معماری را برطرف می کند.
برنامه نویس A از توسعه دهنده B درخواست بررسی می کند.
توسعه دهنده B کد را بررسی می کند و درخواست PR را تأیید می کند (با فرض اینکه خطای دیگری وجود نداشته باشد).
همانطور که می بینیم، با امکان اجرای تست های معماری به صورت محلی و در خط لوله CI، می تواند بازخورد فوری ارائه دهد که توسعه دهنده دیگر را درگیر نمی کند. این بدان معناست که توسعهدهنده A میتواند مشکلات را قبل از درگیر شدن برنامهنویس B در فرآیند تأیید شناسایی و برطرف کند. این امر روند توسعه را سرعت می بخشد و زمان مورد نیاز توسعه دهنده دیگر را برای بررسی کد و جستجوی مسائل معماری کاهش می دهد.
بهبود کیفیت و سازگاری کد
اجرای استانداردها و سازگاری در مراحل اولیه پروژه می تواند به بهبود کیفیت کلی کد کمک کند. این به پیاده سازی مجموعه معقولی از قوانین کمک می کند که توسعه دهندگان می توانند از آنها پیروی کنند تا مطمئن شوند کدی را می نویسند که سایر توسعه دهندگان بتوانند آن را درک کنند.
هر توسعه دهنده ای متد خاص خود را برای نوشتن کد دارد. من مطمئن هستم که شما موافق خواهید بود که وقتی مدت زمان کافی روی یک پروژه کار کردید، معمولاً می توانید تشخیص دهید که چه کسی یک قطعه کد خاص را با نام متغیرها و متدها یا ساختار کلاس ها نوشته است. تفاوتهای جزئی مانند این معمولاً تا زمانی که از استانداردهای کلی پروژه پیروی میکنند که سایر توسعهدهندگان نیز از آن پیروی میکنند، مهم نیستند.
با این حال، اگر استانداردها را اجرا نکنید، پایگاه کد ممکن است تفاوتهای هشداردهندهای داشته باشد. برای مثال، ممکن است یک توسعهدهنده داشته باشید که ترجیح میدهد رابطهای خود را در app/Interfaces
نگه دارد. با این حال، ممکن است توسعهدهنده دیگری داشته باشید که ترجیح میدهد اینترفیسها را در یک پوشه مرتبط با کلاس نگه دارد. به عنوان مثال، آنها ممکن است یک رابط UserServiceInterface
را در پوشه app/Services/User
قرار دهند تا در کنار کلاس UserService
به جای قرار دادن آن در app/Interfaces
.
این نوع تفاوتها میتوانند باعث ایجاد مشکلات سازگاری شوند و درک و کار روی پایگاه کد را برای توسعهدهندگان دیگر دشوار کنند. اگرچه ناهماهنگی هایی مانند اینها باید در طی یک فرآیند بررسی کد دستی مشاهده می شد، اما ممکن است اینطور نبوده باشد. با این حال، اگر میخواهید اعمال کنید که هیچ رابطی خارج از app/Interfaces
وجود ندارد، میتوانید تستهایی مانند این را بنویسید:
test('services namespace only includes classes')
->expect('App\Services')
->toBeClasses();
test('interfaces namespace only contains interfaces')
->expect('App\Interfaces')
->toBeInterfaces();
اکنون، اگر یک رابط در نیم اسپیس App\Services
وجود داشته باشد، تست ناموفق خواهد بود و باید قبل از ادغام کد در شاخه اصلی رفع شود. در نتیجه، می تواند به اطمینان حاصل شود که هر توسعه دهنده ای از یک رویکرد استفاده می کند.
با تست معماری شروع کنید
اکنون که با تست معماری و مزایای آن در پروژه های شما آشنا شدیم، نحوه نصب Pest را یاد می گیریم و اولین تست های معماری خود را می نویسیم.
شما باید Pest را در پروژه لاراول خود با استفاده از Composer نصب کنید. شما می توانید این کار را با اجرای دستور زیر در پوشه اصلی پروژه خود انجام دهید:
composer require pestphp/pest-plugin-laravel --dev
Pest اکنون باید نصب و آماده اجرا شود.
در مرحله بعد، نمونههای معمولی از تستهای معماری را که ممکن است بخواهید به برنامههای لاراول خود اضافه کنید، بررسی میکنیم. ما با ایجاد یک تست ساده شروع می کنیم که ادعا می کند نیم اسپیس App\Models
فقط شامل کلاس ها است و هر کلاس extends می کند از Illuminate\Database\Eloquent\Model
.
جایی که تست های معماری خود را قرار می دهید ترجیح شخصی است، اما من دوست دارم تست های خود را در دایرکتوری tests/Architecture
قرار دهم. انجام این کار به من اجازه می دهد تا تست های معماری خود را جدا از تست های ویژگی و واحد خود نگه دارم. برای اینکه تست های ما در داخل آن دایرکتوری شناسایی و اجرا شوند، باید فایل phpunit.xml
را به روز کنیم تا شامل آن شود. ما می توانیم این کار را با اضافه کردن یک مجموعه تستی معماری جدید به بخش <testsuites>
انجام دهیم:
<testsuites>
...
<testsuite name="Architecture">
<directory>tests/Architecture</directory>
</testsuite>
</testsuites>
اگر قبلاً هیچ تغییری در فایل پیشفرض phpunit.xml
که با لاراول ارسال میشود، ایجاد نکردهاید، این باعث میشود که فایل چیزی شبیه به این باشد:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
>
<testsuites>
<testsuite name="Unit">
<directory>tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory>tests/Feature</directory>
</testsuite>
<testsuite name="Architecture">
<directory>tests/Architecture</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory>app</directory>
</include>
</source>
<php>
<env name="APP_ENV" value="testing"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_DRIVER" value="array"/>
<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>
</phpunit>
من دوست دارم تست های معماری خود را به گونه ای ساختار دهم که شبیه ساختار دایرکتوری کد برنامه من باشد. با انجام این کار، یافتن تست هایی که مربوط به بخش خاصی از پروژه هستند را آسان تر می کند. برای مثال، من تستهای معماری خود را برای مدلها (که در app/Models
یافت میشوند) در یک فایل تستی tests/Architecture/ModelsTest.php
قرار میدهم. من تست های معماری کنترلر خود را (در app/Http/Controllers
) در یک فایل تست tests/Architecture/Http/ControllersTest.php
قرار دادم. و غیره.
بنابراین ما یک فایل tests/Architecture/ModelsTest.php
ایجاد می کنیم و کد زیر را به آن اضافه می کنیم:
use Illuminate\Database\Eloquent\Model;
test('models extends base model')
->expect('App\Models')
->toExtend(Model::class);
اکنون می توانیم این تست را با استفاده از دستور زیر اجرا کنیم:
php artisan test
اگر همه چیز را به درستی پیکربندی کرده باشید، هنگام اجرای تست باید خروجی مانند زیر را ببینید:
PASS Tests\Architecture\ModelsTest
✓ models extends base model 0.06s
Tests: 1 passed (2 assertions)
Duration: 0.14s
ما عمداً تستها را میشکنیم تا مطمئن شویم که تست شما به درستی کار میکند و هر گونه مشکل معماری را تشخیص میدهد. برای انجام این کار، اجازه دهید یک کلاس PHP خالی اضافه کنیم که کلاس Illuminate\Database\Eloquent\Model
را extend نمی کند. کلاس ممکن است چیزی شبیه به این باشد:
namespace App\Models;
class UserService
{
}
اگر تستها را دوباره اجرا کنید، تستها باید با شکست مواجه شوند و خروجیای به شکل زیر دریافت خواهید کرد:
FAIL Tests\Architecture\ModelsTest
⨯ models extends base model 0.07s
──────────────────────────────────────────────────────────----------------------------
FAILED Tests\Architecture\ModelsTest > models ArchExpectationFailedException
Expecting 'app/Models/UserService.php' to extend 'Illuminate\Database\Eloquent\Model'.
at app/Models/UserService.php:5
1▕
2▕
3▕ namespace App\Models;
4▕
➜ 5▕ class UserService
6▕ {
7▕
8▕ }
9▕
1 app/Models/UserService.php:5
Tests: 1 failed (2 assertions)
Duration: 0.18s
نمونه های رایج آزمون های معماری
اکنون که نحوه نصب Pest و نوشتن اولین تست های معماری خود را بررسی کردیم، به چند نمونه معمول از تست های معماری که ممکن است بخواهید به برنامه های Laravel خود اضافه کنید نگاهی بیاندازیم.
در اینجا برخی از متدهای رایجی که احتمالاً در تستهای خود استفاده خواهید کرد، آمده است:
toBeAbstract
- ادعا کنید که کلاس ها در namespace داده شده انتزاعی هستند (با استفاده از کلمه کلیدی abstract
).toBeClasses
- ادعا کنید که فایل ها در namespace داده شده کلاس های PHP هستند.toBeEnums
- ادعا کنید که فایلهای موجود در namespace داده شده، PHP هستند.toBeInterfaces
- ادعا کنید که فایل ها در namespace داده شده رابط PHP هستند.toBeTraits
- ادعا کنید که فایل های موجود در namespace داده شده Traits
های PHP هستند.toBeInvokable
- بیان کنید که کلاسهای موجود در namespace داده شده قابل فراخوانی هستند (به این معنی که آنها یک متد invoke__
دارند).toBeFinal
- ثابت کنید که کلاس ها در namespace داده شده final هستند (با استفاده از کلمه کلیدی final).toBeReadonly
- بیان کنید که کلاس ها در namespace داده شده فقط خواندنی هستند (با استفاده از کلمه کلیدی Readonly
).toExtend
- کلاس ها را در namespace مشخص شده، کلاس داده شده را extend می کند.toImplement
- کلاسها را در namespace مشخص شده Implement
کنید.toHaveMethod
- بیان کنید که کلاس ها در namespace داده شده متد داده شده را دارند.toHavePrefix
- بیان کنید که کلاس ها در namespace مشخص شده با رشته داده شده در نام کلاس خود شروع می شوند.toHaveSuffix
- کلاسها را در namespace مشخص شده با رشته دادهشده در نام کلاسهایشان پایان دهید.toUseStrictTypes
- با استفاده از انواع سخت (با استفاده از کلیدواژههای declare(strict_types=1)
، فایلها را در namespace داده شده مشخص کنید.
شما می توانید اسناد PEST را برای لیست کامل assertions موجود بررسی کنید.
حال، بیایید به چند تست معمولی که ممکن است بخواهید بنویسید نگاه کنیم. این فهرست جامعی نیست، اما باید بینشی در مورد assertions مختلفی که ممکن است بخواهید استفاده کنید ارائه دهد. شما همچنین می توانید از اینها به عنوان نقطه شروع برای تست های خود استفاده کنید و آنها را مطابق با نیازهای خود تغییر دهید.
تست برای دستورات
ممکن است بخواهید یک تست برای دستورات Artisan خود بنویسید تا ادعا کنید که نیم اسپیس App\Console\Commands
فقط شامل کلاس های Command
معتبر است. برای انجام این کار، ممکن است بخواهید تستی مانند این بنویسید:
declare(strict_types=1);
use Illuminate\Console\Command;
test('commands')
->expect('App\Console\Commands')
->toBeClasses()
->toUseStrictTypes()
->toExtend(Command::class)
->toHaveMethod('handle');
در این تست، ما تعریف می کنیم که ما فقط انتظار کلاس هایی را در نیم اسپیس App\Console\Commands
داریم. سپس ادعا می کنیم که هر کلاس از انواع سخت استفاده می کند (با استفاده از declare(strict_types=1
))، کلاس Illuminate\Console\Command
را extend می کند و یک متد handle
دارد.
اگر بخواهیم هر فایلی را در این نیم اسپیس اضافه کنیم که این الزامات را برآورده نمی کند (مانند کلاسی که کلاس Illuminate\Console\Command
را extend نمی کند)، تست با شکست مواجه می شود.
تست برای کنترلرها
همچنین ممکن است بخواهید تستی بنویسید تا ثابت کنید که کنترلرهای شما از استانداردهای خاصی پیروی می کنند. بیایید به نمونه تستی که میتوانید بنویسید نگاهی بیندازیم، و سپس درباره آنچه که انجام میدهیم بحث خواهیم کرد:
declare(strict_types=1);
use Illuminate\Routing\Controller;
test('controllers')
->expect('App\Http\Controllers')
->toBeClasses()
->toUseStrictTypes()
->toBeFinal()
->classes()
->toExtend(Controller::class);
در تست بالا، ما ادعا می کنیم که هر فایل PHP در نیم اسپیس App\Http\Controllers
یک کلاس است. سپس ادعا می کنیم که هر یک از کلاس ها از انواع سخت (با استفاده از declare(strict_types=1
)) و فاینال (با استفاده از کلمه کلیدی Final
) استفاده می کنند. در نهایت، ما ادعا می کنیم که هر کلاس کلاس Illuminate\Routing\Controller
را extend می کند.
اگر بخواهیم کلاسهای دیگری را در این نیم اسپیس اضافه کنیم که این الزامات را برآورده نمیکند (مانند کلاسی که کلاس Illuminate\Routing\Controller
را extend نمی کند.)، تست با شکست مواجه میشود.
تست برای رابط ها
همچنین ممکن است بخواهید تستی بنویسید تا ادعا کنید که نیم اسپیس App\Interfaces
پروژه شما فقط دارای interfaces
است. برای انجام این کار، ممکن است بخواهید تستی مانند این بنویسید:
declare(strict_types=1);
test('interfaces')
->expect('App\Interfaces')
->toBeInterfaces();
اگر بخواهیم هر فایلی را در این نیم اسپیس اضافه کنیم که این الزامات را برآورده نمی کند (مانند افزودن یک کلاس یا ویژگی)، تست با شکست مواجه می شود.
برای آشنایی با تست توسعه محور در لاراول این مقاله را بررسی کنید.
تست برای توابع گلوبال
علاوه بر تست اینکه فایلهای PHP از استانداردهای خاصی پیروی میکنند، میتوانیم تست کنیم که از توابع عمومی PHP خاصی در پایگاه کد خود استفاده نمیکنیم. این می تواند راهی مفید برای اطمینان از اینکه به طور تصادفی کد دیباگ (مانند ()dd
) را در کد باقی نمی گذاریم، که می تواند باعث ایجاد مشکلاتی در production شود.
ممکن است بخواهید تستی مانند این بنویسید:
declare(strict_types=1);
test('globals')
->expect(['dd', 'ddd', 'die', 'dump', 'ray', 'sleep'])
->toBeUsedInNothing();
در تست بالا، ما ادعا می کنیم که توابع dd
، ddd
، die
، dump
، ray
و sleep
در هیچ کجای برنامه استفاده نمی شوند. اگر یکی از آنها را پیدا کند، تست ناموفق خواهد بود.
تست هایی برای JOB ها
مکان مفید دیگری که ممکن است بخواهید برای آن تست های معماری بنویسید، کلاس های جاب شما است. ممکن است بخواهید ادعا کنید که همه کلاسهای جاب شما رابط Illuminate\Contracts\Queue\ShouldQueue
را Implement
میکنند و یک متد handle
دارند. برای انجام این کار، ممکن است بخواهید تستی مانند این بنویسید:
declare(strict_types=1);
use Illuminate\Contracts\Queue\ShouldQueue;
test('jobs')
->expect('App\Jobs')
->toBeClasses()
->toImplement(ShouldQueue::class)
->toHaveMethod('handle');
در تست بالا، ما ادعا میکنیم که نیم اسپیس App\Jobs
فقط شامل کلاسهایی است که رابط Illuminate\Contracts\Queue\ShouldQueue
را Implement
میکنند و یک متد handle
دارند. اگر بخواهیم یک فایل نامعتبر اضافه کنیم (مانند کلاسی که اینترفیس را پیاده سازی نکرده است)، تست با شکست مواجه می شود.
تست برای مدل ها
بیایید به یکی از اصلاحکنندههایی نگاه کنیم که Pest به ما اجازه میدهد از آن برای مشخصتر کردن ادعاهایمان استفاده کنیم. ما نگاهی به اصلاح کننده نادیده می گیریم.
بیایید تصور کنیم که یک App\Models
داریم تا نشان دهیم چگونه میتوانیم از اصلاحکننده «ignoring
» استفاده کنیم. در این دایرکتوری، ما یک دایرکتوری Traits
داریم (با استفاده از نیم اسپیس App\Models\Traits
). تصور کنید که این دایرکتوری حاوی صفاتی است که توسط مدلهای ما استفاده میشود و هیچ جای دیگری در پایگاه کد وجود ندارد.
ممکن است بخواهیم سه تست بنویسیم که شبیه این هستند:
test('models')
->expect('App\Models')
->toBeClasses()
->ignoring('App\Models\Traits');
test('models extends base model')
->expect('App\Models')
->toExtend(Model::class)
->ignoring('App\Models\Traits');
test('model traits')
->expect('App\Models\Traits')
->toBeTraits()
->toOnlyBeUsedIn('App\Models');
در اولین تست (مدلهای نامگذاری شده)، ادعا میکنیم که هر فایل PHP در نیم اسپیس App\Models
یک کلاس است. سپس از اصلاح کننده ignoring
برای نادیده گرفتن نیم اسپیس App\Models\Traits
استفاده می کنیم. این بدان معنی است که این تست هر فایلی را در این نیم اسپیس نادیده می گیرد.
در تست دوم (مدلهای نامگذاری شده، مدل پایه را extend می کنند)، ما ادعا میکنیم که هر کلاس (به جز کلاسهایی که در نیم اسپیس App\Models\Traits
هستند) کلاس Illuminate\Database\Eloquent\Model
را extend کنند، بنابراین آن را به یک کلاس مدل معتبر تبدیل میکنند.
در نهایت، در تست سوم (Trait های مدل نامگذاری شده)، ادعا میکنیم که هر فایل PHP در نیم اسپیس App\Models\Traits
یک Trait است. سپس ادعا می کنیم که ویژگی های موجود در این نیم اسپیس خارج از نیم اسپیس App\Models
زندگی نمی کنند. این به این معنی است که اگر از هر یک از این ویژگی ها در قسمت دیگری از برنامه (مانند یک کنترلر) استفاده کنیم، تست با شکست مواجه می شود.
نتیجه
در این مقاله با تست معماری و مزایای استفاده از آن آشنا شدیم. ما همچنین نحوه نوشتن تست های معماری برای برنامه های Laravel خود را با استفاده از چارچوب تست محبوب PHP، Pest، بررسی کرده ایم.
اکنون آماده شروع نوشتن تست های معماری برای برنامه های لاراول خود هستید.