در حالی که سادگی یکی از مهمترین عواملی است که توسعه دهندگان، لاراول را انتخاب می کنند، اما روز به روز متوجه می شویم که لاراول چقدر تست ها را ساده تر، سریع تر و بهتر می کند. به تسلط بر تست لاراول بپردازید! بهترین روش ها برای کد بی عیب و باگ را کشف کنید. با فرو رفتن عمیق در تست ها تخصص توسعه خود را بالا ببرید.
لاراول، چارچوب قدرتمند PHP، به دلیل سادگی، انعطافپذیری و ویژگیهای قوی، محبوبیت زیادی در بین توسعهدهندگان به دست آورده است. یکی از جنبه های کلیدی که به موفقیت لاراول کمک می کند، قابلیت های تست جامع آن است. تست بخشی جدایی ناپذیر از فرآیند توسعه است که از قابلیت اطمینان، مقیاس پذیری و نگهداری کد اطمینان می دهد. در این مقاله، ما به بررسی عمیق تست لاراول می پردازیم و بهترین شیوه ها، روش ها و تکنیک ها را برای نوشتن تست های موثر و کارآمد بررسی می کنیم.
اگر عمیقاً در جامعه لاراول جستجو کنید، چیزهای شگفت انگیزی مانند Test Driven Laravel توسط Adam Wathan، مجموعه مهارت تست توسط Jeffrey Way، و Confident Laravel و Tests Generator Shift توسط Jason McCreary را خواهید یافت. تست نویسی کد شما را محکم، قابل پیش بینی و بسیار قابل نگهداری می کند. برای آشنایی با TDD در لاراول این مقاله را بررسی کنید.
تست های واحد (Unit) و ویژگی(Feature)
تست های واحد برای قطعات کوچک یک پایه کد مانند متدها یا ویژگی های یک کلاس نوشته می شوند. معمولاً فقط با تست جزئیات دقیق در سطح پایین سروکار دارد. در مورد ما، برخی از متد ها را روی کلاسهای مدل لاراول تست خواهیم کرد، یعنی مدلسازی اتصالات و روابط بین بخشهای مختلف یک برنامه.
تستهای ویژگی(Feature) فراگیرتر است زیرا بخشهای مختلف یک کد را خلاصه میکند و نحوه عملکرد آنها را تست میکند، مثلاً تستهای فانکشنال و تستهای یکپارچهسازی روی کامپوننت ها، ماژولها و غیره. ما در این پست به تست فانکشنال نمیپردازیم.
سرمایه گذاری در تست واحد: مزایا و رویکرد ها
تست روابط در لاراول
پوشش 100٪ کد در تست کد به سختی قابل دستیابی است، ما نزدیکتر هدف داریم اما برخی از تست ها واقعا خسته کننده هستند. در این مقاله از آنوفل در چند قسمتی به شما کمک کردیم با نوشتن حدود 5 درصد از تستهایی که در همه برنامههای لاراول خود به آن نیاز دارید، به پوشش 100 درصدی کد نزدیکتر شوید.
روابط الکونت (Eloquent relationships) همیشه در هر برنامه لاراول وجود دارد، اما چگونه میتوان مطمئن شد که همه مدلهای مورد انتظار به هم متصل هستند؟ این می تواند برگه تقلب شما برای تست های روابط الکونت باشد. ما میخواهیم تستهایی بنویسیم که مطمئن شوند همه مدلهای ما دارای اتصالات مدل مرتبط هستند و به درستی تنظیم شدهاند. برای تسلط بیشتر به ترفند های الکونت در لاراول این مقاله را بررسی کنید.
کلمه "رابطه" به طور معمول به حداقل دو موجودیت اشاره دارد، بنابراین هر رابطه الکوئنت شامل دو طرف است: (الف) رابطه اول و (ب) رابطه معکوس. (هر یک از مدلها میتوانند به عنوان مدل اول در نظر گرفته شوند، اما معمولاً مدل تأثیرگذارتر یا شبیه به والد به عنوان اول انتخاب میشود). وقتی که تستهای رابطه مدل را مینویسیم، منطقی است که از هر دو طرف درگیر تست بگیریم. بنابراین باید برای هر دو رابطه اول و رابطه معکوس تست بنویسیم.
در بیشتر موارد، از نمونههای رابطه استفاده شده در اسناد رسمی لاراول در این مقاله استفاده میشود. موارد استفاده شما ممکن است متفاوت باشد، به سادگی تست ها را با سناریوی خاص خود تطبیق دهید.
ما در این مقاله از پکیج تست Pest برای تست نویسی استفاده می کنیم که به صورت پیش فرض از لاراول 11 به بعد در لاراول قرار دارد. اگر با این چارچوپ تست آشنا نیستی مقاله تست نویسی در لاراول با Pest را بررسی کنید.
1.روابطه یک به یک رابطه
یک رابطه یک به یک (one-to-one) برای تعریف روابطی استفاده می شود که در آن یک مدل سینگل با یک مدل دیگر رابطه واحد دارد. هر دو مدل می توانند تنها یک نمونه از یکدیگر را داشته باشند.
سناریو:
ما مدل های کاربر و تلفن داریم. کاربر مجاز است فقط یک شماره تلفن را در برنامه ثبت کند، این به معنای یک ورودی تلفن منحصر به فرد برای یک کاربر خاص در جدول تلفن است. این رابطه می تواند به صورت روابط ()hasOne
و ()belongsTo
باشد.
()hasOne
- یک کاربر یک تلفن ثبت شده (FIRST) دارد.
// App/User.php
...
public function phone()
{
return $this->hasOne(Phone::class);
}
تست :
<?php
use App\Models\Phone;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
it('a user has a phone', function () {
$user = User::factory()->create();
$phone = Phone::factory()->create(['user_id' => $user->id]);
// Method 1:
expect($user->phone)->toBeInstanceOf(Phone::class);
// Method 2:
expect($user->phone()->count())->toBe(1);
});
در این تست:
متد 1: استفاده از expect
برای بررسی اینکه phone به کلاس Phone تعلق دارد.
متد 2: استفاده از expect
برای بررسی اینکه رابطه phone وجود دارد و تعداد آن 1 است.
()belongsTo
- هر تلفن ثبت شده متعلق به یک کاربر است
- معکوس رابطه hasOne
.
// App/Phone.php
...
public function user()
{
return $this->belongsTo(User::class);
}
تست :
<?php
use App\Models\Phone;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
it('a phone belongs to a user', function () {
$user = User::factory()->create();
$phone = Phone::factory()->create(['user_id' => $user->id]);
expect($phone->user)->toBeInstanceOf(User::class);
});
در این تست:
استفاده از expect
برای بررسی اینکه user
به کلاس User
تعلق دارد.
2. رابطه یک به چند
یک رابطه یک به چند (One To Many) برای تعریف روابطی استفاده می شود که در آن یک مدل واحد دارای هر مقدار مدل دیگر است.
سناریو:
یک پست وبلاگ با تعداد بی نهایت کامنت یا یک نویسنده (کاربر) با تعداد زیادی مقاله یا کامنت. ما قصد داریم یک تست برای رابطه مدل های پست و کامنت بنویسیم. بنابراین این رابطه می تواند به صورت روابط ()hasMany
و ()belongsTo
باشد.
()hasMany
- یک پست کامنت های زیادی دارد (FIRST).
// App/Post.php
...
public function comments()
{
return $this-\>hasMany(Comment::class);
}
تست :
<?php
use App\Models\Comment;
use App\Models\Post;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Schema;
uses(RefreshDatabase::class);
it('posts database has expected columns', function () {
$this->assertTrue(
Schema::hasColumns('posts', [
'id', 'user_id', 'title', 'body'
])
);
});
it('a post has many comments', function () {
$user = User::factory()->create();
$post = Post::factory()->create(['user_id' => $user->id]);
$comment = Comment::factory()->create(['post_id' => $post->id]);
// Method 1: A comment exists in a post's comment collections.
expect($post->comments->contains($comment))->toBeTrue();
// Method 2: Count that a post comments collection exists.
expect($post->comments->count())->toBe(1);
// Method 3: Comments are related to posts and is a collection instance.
expect($post->comments)->toBeInstanceOf('Illuminate\Database\Eloquent\Collection');
});
در این تست:
posts database has expected columns
: بررسی میکند که جدول posts
دارای ستونهای id
، user_id
، title
و body
است.a post has many comments
: بررسی میکند که یک پست دارای چندین کامنت است:
متد 1: بررسی میکند که یک کامنت در مجموعه کامنتهای پست وجود دارد.
متد 2: بررسی میکند که تعداد کامنتهای یک پست برابر با 1 است.
متد 3: بررسی میکند که کامنتهای مربوط به پست یک نمونه از Illuminate\Database\Eloquent\Collection
هستند.()belongsTo
- یک کامنت متعلق به یک پست است
- معکوس رابطه hasMany
.
// App/Comment.php
...
public function user()
{
return $this-\>belongsTo(Post::class);
}
تست :
<?php
use App\Models\Comment;
use App\Models\Post;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Schema;
uses(RefreshDatabase::class);
it('comments database has expected columns', function () {
$this->assertTrue(
Schema::hasColumns('comments', [
'id', 'user_id', 'post_id', 'body'
])
);
});
it('a comment belongs to a post', function () {
$user = User::factory()->create();
$post = Post::factory()->create(['user_id' => $user->id]);
$comment = Comment::factory()->create(['post_id' => $post->id]);
// Method 1: Test by count that a comment has a parent relationship with post
expect($comment->post()->count())->toBe(1);
// Method 2:
expect($comment->post)->toBeInstanceOf(Post::class);
});
در این تست:
comments database has expected columns
: بررسی میکند که جدول comments
دارای ستونهای id
، user_id
، post_id
و body
است.a comment belongs to a post
: بررسی میکند که یک کامنت به یک پست تعلق دارد:
متد 1: بررسی میکند که تعداد رابطههای والد یک کامنت با پست برابر با 1 است.
متد 2: بررسی میکند که رابطه post
یک نمونه از کلاس Post
است.
برای آشنایی با تست معماری در لاراول این مقاله را بررسی کنید.
برای آشنایی با دستورات Artisan و نحوه ایجاد دستورات و فرآیند ها در لاراول این مقاله را بررسی کنید.
3. رابطه چند به چند
یک رابطه چند به چند (many-to-many) برای تعریف روابطی استفاده می شود که در آن دو مدل درگیر می توانند نمونه های زیادی از یکدیگر داشته باشند.
سناریو:
یک کاربر می تواند نقش های زیادی را ایفا کند و نقش ها توسط سایر کاربران نیز به اشتراک گذاشته می شود. همچنین برای پزشکان و تخصص های پزشکی، یک تخصص می تواند توسط بسیاری از پزشکان به اشتراک گذاشته شود در حالی که یک پزشک می تواند در بسیاری از تخصص ها متخصص باشد. تست ما برای رابطه کاربر و مدل Role
خواهد بود.
belongsTo
به معنای مدلی است که از قبل موجود است و مدل دیگری با آن مطابقت دارد اما هیچ امتیازی برای ایجاد آن ندارد. این با hasOne
یا hasMany
متفاوت است که فعل آنها نشان می دهد که یک مدل خاص مالک یا ایجاد مدل دیگری است. در هر دو مدل درگیر ، این رابطه به عنوان belongsTo
تعریف می شود.
()belongsToMany
- یک کاربر به نقش های زیادی تعلق دارد (FIRST).
// App/User.php
...
public function roles()
{
return $this-\>belongsToMany(Role::class);
}
تست :
<?php
use App\Models\Role;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
it('a user belongs to many roles', function () {
$user = User::factory()->create();
$role = Role::factory()->create();
// Attach role to user
$user->roles()->attach($role);
// Method 1: Check if the roles relationship returns a collection
expect($user->roles)->toBeInstanceOf('Illuminate\Database\Eloquent\Collection');
});
در این تست :
a user belongs to many roles
: بررسی میکند که یک کاربر میتواند چندین نقش داشته باشد و رابطه roles
یک مجموعه (collection
) از نقشها را برمیگرداند.
متد 1: بررسی میکند که رابطه roles
یک نمونه از Illuminate\Database\Eloquent\Collection
است.
()belongsToMany
- یک نقش به بسیاری از کاربران تعلق دارد
- معکوس رابطه belongsToMany. نوعی بازگشتی
// App/Role.php
...
public function users()
{
return $this-\>belongsToMany(User::class);
}
تست:
<?php
use App\Models\Role;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
it('a user belongs to many roles', function () {
$user = User::factory()->create();
$role = Role::factory()->create();
// Attach role to user
$user->roles()->attach($role);
// Method 1: Check if the roles relationship returns a collection
expect($user->roles)->toBeInstanceOf('Illuminate\Database\Eloquent\Collection');
});
در این تست:
roles database has expected columns
: بررسی میکند که جدول roles
دارای ستونهای id
، title
و description
است.a role belongs to many users
: بررسی میکند که یک نقش میتواند به چندین کاربر تعلق داشته باشد و رابطه users
یک مجموعه (collection
) از کاربران را برمیگرداند.
متد 1: بررسی میکند که رابطه users
یک نمونه از Illuminate\Database\Eloquent\Collection
است.
برای آشنایی با معماری ماژولار در لاراول این مقاله را بررسی کنید.
9 تا از بهترین روش های تست نویسی در لاراول در سال 2024
لاراول با داکر آشنایی با Laravel Sail
4. رابطه Has One Through
رابطه "Has One Through" مدل ها را از طریق یک رابطه میانی منفرد لینک می دهد.
سناریو:
با توجه به اینکه یک تامین کننده یک کاربر دارد و هر کاربر با History
کاربر مرتبط است، مدل تامین کننده ممکن است از طریق مدل کاربر میانی به تاریخچه کاربر دسترسی داشته باشد.
()hasOneThrough
- یک تامین کننده یک سابقه از طریق یک کاربر دارد
- هیچ رابطه INVERSE رسمی ندارد.
// App/Supplier.php
...
public function userHistory()
{
return $this->hasOneThrough(History::class, User::class);
}
تست :
<?php
use App\Models\History;
use App\Models\Supplier;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Schema;
uses(RefreshDatabase::class);
it('suppliers database has expected columns', function () {
$this->assertTrue(
Schema::hasColumns('suppliers', [
'id', 'name', 'services'
])
);
});
it('a supplier has a history through user', function () {
$supplier = Supplier::factory()->create();
$user = User::factory()->create(['supplier_id' => $supplier->id]);
$history = History::factory()->create(['user_id' => $user->id]);
// Method 1: Check if userHistory is an instance of History
expect($supplier->userHistory)->toBeInstanceOf(History::class);
// Method 2: Check if the userHistory relationship returns one history
expect($supplier->userHistory()->count())->toBe(1);
});
در این تست :
suppliers database has expected columns
: بررسی میکند که جدول suppliers
دارای ستونهای id
، name
و services
است.a supplier has a history through user
: بررسی میکند که یک Supplier
دارای یک History
از طریق User
است:
متد 1: بررسی میکند که userHistory
یک نمونه از کلاس History
است.
متد 2: بررسی میکند که رابطه userHistory
یک تاریخچه را برمیگرداند و تعداد آن 1 است.
روابط " hasThrough" رابطه معکوس رسمی ندارند زیرا مدل های مربوطه همیشه به طور غیرمستقیم مرتبط هستند، اما می توان با پیوند دادن از طریق مدل میانی مانند زیر، معکوس کرد، با این حال، مراقب مسائل n+1
و بارگذاری lazy در صورت لزوم باشید.
// App/History.php
...
/**
* With this attribute defined it can be used as **$this-\>supplier**
*/
public function getSupplierAttribute()
{
return $this->user->supplier;
}
5. رابطه Has Many Through
درست همانطور که رابطه «Has One Through» یک مدل مرتبط دور را از طریق یک رابطه میانی به هم پیوند میدهد، «Has Many Through» نیز همین کار را میکند اما میتواند به بسیاری از نمونههای مدل مرتبط دور اشاره کند.
سناریو:
یک مدل Country
ممکن است چندین مدل Post را از طریق یک مدل کاربر متوسط داشته باشد. ما تستی می نویسیم که تضمین می کند می توان به پست های وبلاگ برای یک کشور خاص در نمونه Country
با یک رابطه hasManyThrough
دسترسی داشت.
()hasManyThrough
- یک Country
می تواند از طریق یک مدل کاربر پست های زیادی داشته باشد
- هیچ رابطه REVERSE رسمی ندارد
// App/Country.php
...
public function posts()
{
return $this->hasManyThrough(Post::class, User::class);
}
تست :
<?php
use App\Models\Country;
use App\Models\Post;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Schema;
uses(RefreshDatabase::class);
beforeEach(function () {
$this->country = Country::factory()->create();
$this->user = User::factory()->create(['country_id' => $this->country->id]);
$this->post = Post::factory()->create(['user_id' => $this->user->id]);
});
it('countries database has expected columns', function () {
$this->assertTrue(
Schema::hasColumns('countries', [
'id', 'name', 'population'
])
);
});
it('a country has many posts through user', function () {
// Method 1: Check if the post exists in the country's posts collection
expect($this->country->posts->contains($this->post))->toBeTrue();
// Method 2: Check if the number of posts is correct
expect($this->country->posts->count())->toBe(1);
// Method 3: Check if the posts relationship returns a collection
expect($this->country->posts)->toBeInstanceOf('Illuminate\Database\Eloquent\Collection');
});
در این تست :
countries database has expected columns
: بررسی میکند که جدول countries
دارای ستونهای id
، name
و population
است.a country has many posts through user
: بررسی میکند که یک کشور دارای چندین پست از طریق کاربران است:
متد 1: بررسی میکند که پست مورد نظر در مجموعه پستهای کشور وجود دارد.
متد 2: بررسی میکند که تعداد پستهای کشور برابر با 1 است.
متد 3: بررسی میکند که رابطه posts
یک مجموعه (collection) از پستها را برمیگرداند.
روابط "hasThrough
" رابطه معکوس رسمی ندارند، اما می توان با لینک دادن از طریق مدل میانی مانند زیر، یک معکوس را انجام داد (مراقب مسائل n+1
و بارگذاری eager در صورت لزوم):
// App/Post.php
...
/**
* With this attribute defined it can be used as **$this->country**
*/
public function getCountryAttribute()
{
return $this->user->country;
}
روابط چند شکلی
یک رابطه چند شکلی به یک مدل هدف اجازه می دهد تا با استفاده از یک ارتباط واحد به بیش از یک نوع مدل تعلق داشته باشد.
1. رابطه چند شکلی یک به یک
یک رابطه چند شکلی یک به یک(one-to-one polymorphic) شبیه یک رابطه ساده یک به یک است. با این حال، مدل هدف می تواند به بیش از یک نوع مدل در یک انجمن واحد تعلق داشته باشد.
سناریو:
یک پست وبلاگ و یک کاربر ممکن است یک رابطه چند شکلی با یک مدل تصویر به اشتراک بگذارند. استفاده از یک رابطه چند شکلی یک به یک به شما امکان می دهد یک لیست واحد از تصاویر منحصر به فرد داشته باشید که هم برای پست های وبلاگ و هم برای حساب های کاربری استفاده می شود.
()morphTo
- یک جدول تصویر را می توان به هر مدلی تغییر داد (یعنی مدل های مختلف را ارائه می دهد)، به عنوان مثال مدل کاربر یا پست در مورد ما.
// App/Image.php
...
public function imageable()
{
return $this->morphTo();
}
تست :
<?php
use App\Models\Country;
use App\Models\Image;
use App\Models\Post;
use App\Models\Supplier;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Schema;
uses(RefreshDatabase::class);
beforeEach(function () {
$this->user = User::factory()->create();
$this->post = Post::factory()->create();
$this->image = Image::factory()->create();
});
it('images database has expected columns', function () {
$this->assertTrue(Schema::hasColumns('images', [
'id', 'url', 'imageable_id', 'imageable_type'
]));
});
it('an image can be uploaded by a user', function () {
$image = Image::factory()->create([
'imageable_id' => $this->user->id,
'imageable_type' => 'App\Models\User',
]);
expect($image->imageable)->toBeInstanceOf(User::class);
});
it('an image can be uploaded for a post', function () {
$image = Image::factory()->create([
'imageable_id' => $this->post->id,
'imageable_type' => 'App\Models\Post',
]);
expect($image->imageable)->toBeInstanceOf(Post::class);
});
در این تست :
images database has expected columns
: بررسی میکند که جدول images دارای ستونهای id، url، imageable_id و imageable_type است.an image can be uploaded by a user
: بررسی میکند که یک تصویر میتواند به یک کاربر تعلق داشته باشد و رابطه imageable یک نمونه از کلاس User است.an image can be uploaded for a post
: بررسی میکند که یک تصویر میتواند به یک پست تعلق داشته باشد و رابطه imageable یک نمونه از کلاس Post است.
()morphOne
- یک مدل کاربر/پست میتواند یک نمونه از جدول مدل تصویر مشابه را تغییر دهد (یعنی از همان جدول تصویر استفاده کند اما یک رکورد در هر کاربر/پست).
- معکوس رابطه morphTo
.
// App/User.php
...
public function image()
{
return $this->morphOne(Image::class, 'imageable');
}
تست :
<?php
use App\Models\Image;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
beforeEach(function () {
$this->user = User::factory()->create();
$this->image = Image::factory()->create([
'imageable_id' => $this->user->id,
'imageable_type' => 'App\Models\User',
]);
});
it('a user morphs one image', function () {
expect($this->user->image)->toBeInstanceOf(Image::class);
});
در این تست :
a user morphs one image
: بررسی میکند که یک کاربر میتواند یک تصویر داشته باشد و رابطه image یک نمونه از کلاس Image است.
2. یک به چند (چند شکلی)
یک رابطه چند شکلی یک به چند (one-to-many polymorphic) شبیه به یک رابطه ساده یک به چند است. با این حال، مدل هدف می تواند به بیش از یک نوع مدل در یک انجمن واحد تعلق داشته باشد.
سناریو:
کاربران برنامه شما میتوانند هم در مورد پستها و هم روی ویدیوها «نظر بدهند». با استفاده از روابط چند شکلی، میتوانید از یک جدول کامنت ها برای هر دوی این سناریوها استفاده کنید.
()morphTo
- یک جدول کامنت را می توان به هر مدلی تغییر داد (یعنی مدل های مختلف را ارائه می دهد)، به عنوان مثال مدل ویدیو یا پست در مورد ما.
// App/Comment.php
...
public function commentable()
{
return $this->morphTo();
}
تست :
<?php
use App\Models\Comment;
use App\Models\Country;
use App\Models\Post;
use App\Models\Supplier;
use App\Models\User;
use App\Models\Video;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
beforeEach(function () {
$this->country = Country::factory()->create();
$this->supplier = Supplier::factory()->create();
$this->user = User::factory()->create();
$this->post = Post::factory()->create();
$this->video = Video::factory()->create();
$this->comment = Comment::factory()->create();
});
it('a comment can be morphed to a video model', function () {
$comment = Comment::factory()->create([
'commentable_id' => $this->video->id,
'commentable_type' => Video::class,
]);
expect($comment->commentable)->toBeInstanceOf(Video::class);
});
it('a comment can be morphed to a post model', function () {
$comment = Comment::factory()->create([
'commentable_id' => $this->post->id,
'commentable_type' => Post::class,
]);
expect($comment->commentable)->toBeInstanceOf(Post::class);
});
در این تست :
a comment can be morphed to a video model
: بررسی میکند که یک کامنت میتواند به یک مدل Video تعلق داشته باشد و رابطه commentable
یک نمونه از کلاس Video است.a comment can be morphed to a post model
: بررسی میکند که یک کامنت میتواند به یک مدل Post تعلق داشته باشد و رابطه commentable
یک نمونه از کلاس Post است.
()morphMany
- یک مدل ویدیو/پست میتواند بسیاری از نمونههای جدول مدل نظر یکسان را تغییر دهد (یعنی از جدول نظرات یکسان برای بسیاری از رکوردها استفاده کند).
- معکوس رابطه morphTo
.
// App/Video.php
...
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
تست :
<?php
use App\Models\Comment;
use App\Models\Country;
use App\Models\Post;
use App\Models\Supplier;
use App\Models\User;
use App\Models\Video;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Schema;
uses(RefreshDatabase::class);
beforeEach(function () {
$this->country = Country::factory()->create();
$this->supplier = Supplier::factory()->create();
$this->user = User::factory()->create();
$this->post = Post::factory()->create(['user_id' => $this->user->id]);
$this->video = Video::factory()->create(['user_id' => $this->user->id]);
$this->comment = Comment::factory()->create([
'commentable_id' => $this->video->id,
'commentable_type' => Video::class,
]);
});
it('videos database has expected columns', function () {
$this->assertTrue(
Schema::hasColumns('videos', [
'id', 'user_id', 'title', 'description', 'size', 'length'
])
);
});
it('a video morphs many comments', function () {
expect($this->video->comments)->toBeInstanceOf('Illuminate\Database\Eloquent\Collection');
});
در این تست :
videos database has expected columns
: بررسی میکند که جدول videos دارای ستونهای id، user_id، title، description، size و length است.a video morphs many comments
: بررسی میکند که یک مدل Video میتواند نظرات زیادی داشته باشد و رابطه comments یک نمونه از Illuminate\Database\Eloquent\Collection
است.
3. رابطه چند به چند (چند شکلی)
فرض کنید سه مدل Post، Video و Tag داریم که Post و Video به صورت پلیمورفیک به Tag متصل هستند.
class Post extends Model
{
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
}
تست :
<?php
use App\Models\Post;
use App\Models\Video;
use App\Models\Tag;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
it('can attach tags to a post', function () {
$post = Post::create(['title' => 'My first post']);
$tag1 = Tag::create(['name' => 'Laravel']);
$tag2 = Tag::create(['name' => 'PHP']);
$post->tags()->attach([$tag1->id, $tag2->id]);
expect($post->tags()->count())->toBe(2);
expect($post->tags->pluck('name')->toArray())->toEqual(['Laravel', 'PHP']);
});
it('can attach tags to a video', function () {
$video = Video::create(['title' => 'My first video']);
$tag1 = Tag::create(['name' => 'Tutorial']);
$tag2 = Tag::create(['name' => 'Educational']);
$video->tags()->attach([$tag1->id, $tag2->id]);
expect($video->tags()->count())->toBe(2);
expect($video->tags->pluck('name')->toArray())->toEqual(['Tutorial', 'Educational']);
});
در این تست :
تست can attach tags to a post
:
این تست بررسی میکند که آیا میتوان تگ ها را به مدل Post متصل کرد یا خیر. مراحل تست به شرح زیر است:
ایجاد پست جدید: یک پست جدید با عنوان "My first post" ایجاد میشود.
ایجاد تگ ها: دو تگ جدید با نامهای "Laravel" و "PHP" ایجاد میشود.
اتصال تگها به پست: تگها به پست متصل میشوند.
بررسی تعداد تگها: با استفاده از متد ()count
تعداد تگهای متصل شده به پست بررسی میشود که باید برابر با ۲ باشد.
بررسی نام تگها: نام تگها استخراج شده و با نامهای مورد انتظار ['Laravel', 'PHP'] مقایسه میشود.
به طور کلی، این تست اطمینان حاصل میکند که تگها به درستی به پست متصل شده و میتوان به اطلاعات تگها دسترسی پیدا کرد.
تست can attach tags to a video
:
این تست بررسی میکند که آیا میتوان تگها (tags) را به مدل Video متصل کرد یا خیر. مراحل تست به شرح زیر است:
ایجاد ویدیو جدید: یک ویدیو جدید با عنوان "My first video" ایجاد میشود.
ایجاد تگها: دو تگ جدید با نامهای "Tutorial" و "Educational" ایجاد میشود.
اتصال تگها به ویدیو: تگها به ویدیو متصل میشوند.
بررسی تعداد تگها: با استفاده از متد count() تعداد تگهای متصل شده به ویدیو بررسی میشود که باید برابر با ۲ باشد.
بررسی نام تگها: نام تگها استخراج شده و با نامهای مورد انتظار ['Tutorial', 'Educational'] مقایسه میشود.
نتیجه
تست نویسی بخش جدایی ناپذیر در توسعه یک اپلیکیشن است، ما در این مقاله با تمامی تست های روابط الکونت در لاراول آشنا شدیم و می توانید از این تست ها برای اپلیکیشن های خود استفاده کنید. قابلیتهای تست لاراول، زمانی که به طور موثر مورد استفاده قرار گیرد، به طور قابل توجهی به توسعه برنامههای کاربردی قوی و قابل اعتماد کمک میکند. از تستهای واحد گرفته تا تستهای ویژگی، لاراول یک اکوسیستم تست جامع را ارائه میکند که به توسعهدهندگان اجازه میدهد از عملکرد، امنیت و مقیاسپذیری کد خود اطمینان حاصل کنند.