تست پایگاه داده
- معرفی
- تعریف کارخانه های مدل
- ایجاد مدل ها با استفاده از کارخانه ها
- روابط کارخانه
- در حال اجرا بذرها
- ادعاهای موجود
معرفی
لاراول انواع ابزارها و ادعاهای مفیدی را ارائه می دهد تا آزمایش برنامه های کاربردی مبتنی بر پایگاه داده شما را آسان تر کند. علاوه بر این، کارخانهها و کاشتهای مدل لاراول، ایجاد رکوردهای پایگاه داده آزمایشی را با استفاده از مدلها و روابط Eloquent برنامه شما بدون دردسر میسازند. در مستندات زیر به همه این ویژگی های قدرتمند خواهیم پرداخت.
تنظیم مجدد پایگاه داده پس از هر تست
قبل از اینکه خیلی بیشتر ادامه دهیم، بیایید در مورد چگونگی تنظیم مجدد
پایگاه داده خود پس از هر یک از آزمایشات خود بحث کنیم تا داده های آزمایش قبلی با آزمایش های بعدی تداخل نداشته
باشند.
ویژگی گنجانده شده لاراول
Illuminate\Foundation\Testing\RefreshDatabase
از این موضوع برای شما مراقبت خواهد کرد.
به سادگی از این ویژگی در کلاس آزمایشی خود استفاده کنید:
<?php namespace Tests\Feature; use Illuminate\Foundation\Testing\RefreshDatabase;use Illuminate\Foundation\Testing\WithoutMiddleware;use Tests\TestCase; class ExampleTest extends TestCase{ use RefreshDatabase; /** * A basic functional test example. * * @return void */ public function test_basic_example() { $response = $this->get('/'); // ... }}
تعریف کارخانه های مدل
نمای کلی مفهوم
ابتدا اجازه دهید در مورد کارخانه های مدل Eloquent صحبت کنیم. هنگام آزمایش، ممکن است لازم باشد قبل از اجرای آزمایش، چند رکورد را در پایگاه داده خود وارد کنید. به جای تعیین دستی مقدار هر ستون هنگام ایجاد این داده های آزمایشی، لاراول به شما اجازه می دهد مجموعه ای از ویژگی های پیش فرض را برای هر یک از مدل های Eloquent خود با استفاده از کارخانه های مدل تعریف کنید.
برای مشاهده نمونه ای از نحوه نوشتن یک کارخانه، به
database/factories/UserFactory.php
فایل موجود در برنامه خود نگاهی بیندازید.
این کارخانه با تمام برنامه های جدید لاراول گنجانده شده است و شامل تعریف
کارخانه زیر است:
namespace Database\Factories; use Illuminate\Database\Eloquent\Factories\Factory;use Illuminate\Support\Str; class UserFactory extends Factory{ /** * Define the model's default state. * * @return array */ public function definition() { return [ 'name' => $this->faker->name(), 'email' => $this->faker->unique()->safeEmail(), 'email_verified_at' => now(), 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 'remember_token' => Str::random(10), ]; }}
همانطور که می بینید، کارخانه ها در ابتدایی ترین شکل خود، کلاس هایی هستند
که کلاس کارخانه پایه لاراول را گسترش می دهند و
definition
متد را تعریف می کنند.
این
definition
متد مجموعه پیشفرض مقادیر مشخصهای را که باید هنگام ایجاد یک مدل با
استفاده از کارخانه اعمال شوند، برمیگرداند.
از طریق ویژگی، کارخانه ها به کتابخانه
Faker
faker
PHP دسترسی دارند
، که به شما امکان می دهد انواع مختلفی از داده های تصادفی را برای آزمایش
به راحتی تولید کنید.
faker_locale
میتوانید با افزودن گزینهای بهconfig/app.php
فایل پیکربندی، منطقه Faker برنامه خود را تنظیم کنید .
کارخانه های تولید کننده
برای ایجاد یک کارخانه،
make:factory
دستور Artisan را
اجرا کنید :
php artisan make:factory PostFactory
کلاس کارخانه جدید در
database/factories
دایرکتوری شما قرار می گیرد.
کنوانسیون های کشف مدل و کارخانه
هنگامی که کارخانههای خود را تعریف کردید، میتوانید از
factory
روش استاتیکی که توسط این ویژگی برای مدلهای خود ارائه میشود، استفاده
کنید
Illuminate\Database\Eloquent\Factories\HasFactory
تا نمونهای کارخانهای برای آن مدل ایجاد کنید.
روش این
HasFactory
صفت
factory
از قراردادها برای تعیین کارخانه مناسب برای مدلی که صفت به آن اختصاص داده
شده است استفاده می کند.
به طور خاص، متد به دنبال کارخانه ای در
Database\Factories
فضای نام می گردد که نام کلاسی مطابق با نام مدل داشته باشد و پسوند آن باشد
Factory
.
اگر این قراردادها برای برنامه یا کارخانه خاص شما اعمال نمی شود، می توانید
newFactory
روش را روی مدل خود بازنویسی کنید تا نمونه ای از کارخانه مربوطه مدل را
مستقیماً بازگردانید:
use Database\Factories\Administration\FlightFactory; /** * Create a new factory instance for the model. * * @return \Illuminate\Database\Eloquent\Factories\Factory */protected static function newFactory(){ return FlightFactory::new();}
در مرحله بعد، یک
model
ویژگی در کارخانه مربوطه تعریف کنید:
use App\Administration\Flight;use Illuminate\Database\Eloquent\Factories\Factory; class FlightFactory extends Factory{ /** * The name of the factory's corresponding model. * * @var string */ protected $model = Flight::class;}
ایالات کارخانه
روشهای دستکاری حالت به شما امکان میدهد تا تغییرات گسستهای را تعریف
کنید که میتوانند در هر ترکیبی در کارخانههای مدل شما اعمال شوند.
به عنوان مثال،
Database\Factories\UserFactory
کارخانه شما ممکن است حاوی یک
suspended
روش حالت باشد که یکی از مقادیر مشخصه پیشفرض آن را تغییر میدهد.
روش های تبدیل حالت معمولاً
state
روش ارائه شده توسط کلاس کارخانه پایه لاراول را می نامند.
این
state
روش یک بسته را می پذیرد که آرایه ای از ویژگی های خام تعریف شده برای
کارخانه را دریافت می کند و باید آرایه ای از ویژگی ها را برای اصلاح برگرداند:
/** * Indicate that the user is suspended. * * @return \Illuminate\Database\Eloquent\Factories\Factory */public function suspended(){ return $this->state(function (array $attributes) { return [ 'account_status' => 'suspended', ]; });}
تماس های کارخانه ای
afterMaking
تماسهای کارخانه با استفاده از روشهای و
ثبت میشوند
afterCreating
و به شما اجازه میدهند تا پس از ساخت یا ایجاد یک مدل، کارهای بیشتری را
انجام دهید.
شما باید این کال بک ها را با تعریف
configure
متدی در کلاس کارخانه خود ثبت کنید.
این متد به طور خودکار توسط لاراول زمانی که کارخانه نمونه سازی می شود
فراخوانی می شود:
namespace Database\Factories; use App\Models\User;use Illuminate\Database\Eloquent\Factories\Factory;use Illuminate\Support\Str; class UserFactory extends Factory{ /** * Configure the model factory. * * @return $this */ public function configure() { return $this->afterMaking(function (User $user) { // })->afterCreating(function (User $user) { // }); } // ...}
ایجاد مدل ها با استفاده از کارخانه ها
نمونه سازی مدل ها
هنگامی که کارخانههای خود را تعریف کردید، میتوانید از
factory
روش استاتیکی که توسط این ویژگی برای مدلهای خود ارائه میشود، استفاده
کنید
Illuminate\Database\Eloquent\Factories\HasFactory
تا نمونهای کارخانهای برای آن مدل ایجاد کنید.
بیایید به چند نمونه از ایجاد مدل نگاهی بیندازیم.
make
ابتدا از روشی برای ایجاد مدلها بدون ماندگاری در پایگاه داده
استفاده میکنیم :
use App\Models\User; public function test_models_can_be_instantiated(){ $user = User::factory()->make(); // Use model in tests...}
می توانید با استفاده از
count
روش زیر مجموعه ای از مدل های زیادی ایجاد کنید:
$users = User::factory()->count(3)->make();
کشورهای متقاضی
همچنین می توانید هر یک از حالت های خود را در مدل ها اعمال کنید. اگر می خواهید چندین تبدیل حالت را در مدل ها اعمال کنید، می توانید به سادگی روش های تبدیل حالت را مستقیماً فراخوانی کنید:
$users = User::factory()->count(5)->suspended()->make();
ویژگی های برتر
اگر میخواهید برخی از مقادیر پیشفرض مدلهای خود را لغو کنید، میتوانید
آرایهای از مقادیر را به
make
متد ارسال کنید.
فقط ویژگیهای مشخص شده جایگزین میشوند در حالی که بقیه ویژگیها روی
مقادیر پیشفرض خود که توسط کارخانه مشخص شده است، تنظیم میشوند:
$user = User::factory()->make([ 'name' => 'Abigail Otwell',]);
روش دیگر،
state
ممکن است به طور مستقیم در نمونه کارخانه برای انجام یک تبدیل حالت درون خطی
فراخوانی شود:
$user = User::factory()->state([ 'name' => 'Abigail Otwell',])->make();
هنگام ایجاد مدلها با استفاده از کارخانه ، حفاظت از تخصیص انبوه به طور خودکار غیرفعال میشود.
مدل های ماندگار
این
create
روش نمونههای مدل را نمونهسازی میکند و آنها را با استفاده از روش
Eloquent در پایگاه داده نگهداری میکند
save
:
use App\Models\User; public function test_models_can_be_persisted(){ // Create a single App\Models\User instance... $user = User::factory()->create(); // Create three App\Models\User instances... $users = User::factory()->count(3)->create(); // Use model in tests...}
میتوانید ویژگیهای مدل پیشفرض کارخانه را با ارسال آرایهای از ویژگیها
به
create
متد لغو کنید:
$user = User::factory()->create([ 'name' => 'Abigail',]);
دنباله ها
گاهی اوقات ممکن است بخواهید مقدار یک ویژگی مدل معین را برای هر مدل ایجاد
شده جایگزین کنید.
شما می توانید این کار را با تعریف تبدیل حالت به عنوان یک دنباله انجام
دهید.
به عنوان مثال، ممکن است بخواهید مقدار یک
admin
ستون را بین
Y
و
N
برای هر کاربر ایجاد شده جایگزین کنید:
use App\Models\User;use Illuminate\Database\Eloquent\Factories\Sequence; $users = User::factory() ->count(10) ->state(new Sequence( ['admin' => 'Y'], ['admin' => 'N'], )) ->create();
در این مثال، پنج کاربر با
admin
مقدار
Y
و پنج کاربر با
admin
مقدار ایجاد خواهند شد
N
.
در صورت لزوم، می توانید یک بسته را به عنوان مقدار توالی اضافه کنید. هر بار که دنباله به یک مقدار جدید نیاز دارد، بسته شدن فراخوانی می شود:
$users = User::factory() ->count(10) ->state(new Sequence( fn ($sequence) => ['role' => UserRoles::all()->random()], )) ->create();
در بسته شدن توالی، میتوانید به
$index
یا
$count
ویژگیهای نمونه دنبالهای که به بسته تزریق میشود دسترسی داشته باشید.
این
$index
ویژگی شامل تعداد تکرارها از طریق دنباله ای است که تاکنون رخ داده است، در
حالی که
$count
ویژگی شامل تعداد کل دفعاتی است که دنباله فراخوانی می شود:
$users = User::factory() ->count(10) ->sequence(fn ($sequence) => ['name' => 'Name '.$sequence->index]) ->create();
روابط کارخانه
روابط زیادی دارد
سپس، بیایید ایجاد روابط مدل Eloquent را با استفاده از روشهای کارخانه
روان لاراول بررسی کنیم.
ابتدا فرض کنید برنامه ما دارای یک
App\Models\User
مدل و یک
App\Models\Post
مدل است.
همچنین، فرض کنیم که
User
مدل
hasMany
رابطه ای را با
Post
.
has
ما می توانیم با استفاده از روش ارائه شده توسط کارخانه های لاراول،
کاربری ایجاد کنیم که دارای سه پست باشد .
این
has
روش یک نمونه کارخانه را می پذیرد:
use App\Models\Post;use App\Models\User; $user = User::factory() ->has(Post::factory()->count(3)) ->create();
طبق قرارداد، هنگام انتقال یک
Post
مدل به
has
روش، لاراول فرض میکند که
User
مدل باید
posts
متدی داشته باشد که رابطه را تعریف کند.
در صورت لزوم، می توانید به صراحت نام رابطه ای را که می خواهید دستکاری
کنید، مشخص کنید:
$user = User::factory() ->has(Post::factory()->count(3), 'posts') ->create();
البته، ممکن است دستکاری های حالت را روی مدل های مرتبط انجام دهید. علاوه بر این، اگر تغییر حالت شما نیاز به دسترسی به مدل والد داشته باشد، میتوانید یک تبدیل حالت مبتنی بر بسته شدن را تصویب کنید:
$user = User::factory() ->has( Post::factory() ->count(3) ->state(function (array $attributes, User $user) { return ['user_type' => $user->type]; }) ) ->create();
استفاده از روش های جادویی
برای راحتی، می توانید از روش های رابطه کارخانه جادویی لاراول برای ایجاد
روابط استفاده کنید.
به عنوان مثال، مثال زیر از قرارداد استفاده می کند تا مشخص کند که مدل های
مرتبط باید از طریق یک
posts
روش رابطه در
User
مدل ایجاد شوند:
$user = User::factory() ->hasPosts(3) ->create();
هنگام استفاده از روشهای جادویی برای ایجاد روابط کارخانه، میتوانید آرایهای از ویژگیها را برای نادیده گرفتن مدلهای مرتبط ارسال کنید:
$user = User::factory() ->hasPosts(3, [ 'published' => false, ]) ->create();
اگر تغییر حالت شما نیاز به دسترسی به مدل والد داشته باشد، میتوانید یک تبدیل حالت مبتنی بر بسته شدن ارائه دهید:
$user = User::factory() ->hasPosts(3, function (array $attributes, User $user) { return ['user_type' => $user->type]; }) ->create();
متعلق به روابط است
اکنون که نحوه ایجاد روابط "بسیار" با استفاده از کارخانه ها را بررسی
کردیم، اجازه دهید معکوس این رابطه را بررسی کنیم.
این
for
روش ممکن است برای تعریف مدل مادری که مدلهای ایجاد شده کارخانه به آن تعلق
دارند، استفاده شود.
به عنوان مثال، ما می توانیم سه
App\Models\Post
نمونه مدل ایجاد کنیم که متعلق به یک کاربر است:
use App\Models\Post;use App\Models\User; $posts = Post::factory() ->count(3) ->for(User::factory()->state([ 'name' => 'Jessica Archer', ])) ->create();
اگر قبلاً یک نمونه مدل والد دارید که باید با مدلهایی که ایجاد میکنید
مرتبط باشد، میتوانید نمونه مدل را به متد ارسال کنید
for
:
$user = User::factory()->create(); $posts = Post::factory() ->count(3) ->for($user) ->create();
استفاده از روش های جادویی
برای راحتی، میتوانید از روشهای رابطه کارخانه جادویی لاراول برای تعریف
روابط «متعلق به» استفاده کنید.
به عنوان مثال، مثال زیر از قرارداد استفاده می کند تا تعیین کند که سه پست
باید به
user
رابطه روی
Post
مدل تعلق داشته باشند:
$posts = Post::factory() ->count(3) ->forUser([ 'name' => 'Jessica Archer', ]) ->create();
بسیاری از روابط
مانند
بسیاری از روابط
، روابط "بسیاری از بسیاری" ممکن است با استفاده از
has
روش ایجاد شوند:
use App\Models\Role;use App\Models\User; $user = User::factory() ->has(Role::factory()->count(3)) ->create();
ویژگی های جدول محوری
اگر نیاز به تعریف ویژگی هایی دارید که باید در جدول محوری / میانی که مدل
ها را به هم پیوند می دهد تنظیم شود، می توانید از
hasAttached
روش استفاده کنید.
این متد آرایه ای از نام ها و مقادیر ویژگی های جدول محوری را به عنوان
آرگومان دوم خود می پذیرد:
use App\Models\Role;use App\Models\User; $user = User::factory() ->hasAttached( Role::factory()->count(3), ['active' => true] ) ->create();
اگر تغییر حالت شما نیاز به دسترسی به مدل مرتبط داشته باشد، میتوانید یک تبدیل حالت مبتنی بر بسته شدن ارائه دهید:
$user = User::factory() ->hasAttached( Role::factory() ->count(3) ->state(function (array $attributes, User $user) { return ['name' => $user->name.' Role']; }), ['active' => true] ) ->create();
اگر قبلاً نمونههای مدلی دارید که میخواهید به مدلهایی که ایجاد میکنید
متصل شوند، میتوانید نمونههای مدل را به متد ارسال کنید
hasAttached
.
در این مثال، همان سه نقش به هر سه کاربر پیوست میشود:
$roles = Role::factory()->count(3)->create(); $user = User::factory() ->count(3) ->hasAttached($roles, ['active' => true]) ->create();
استفاده از روش های جادویی
برای راحتی، میتوانید از روشهای رابطه کارخانه جادویی لاراول برای تعریف
بسیاری از روابط استفاده کنید.
به عنوان مثال، مثال زیر از قرارداد استفاده می کند تا مشخص کند که مدل های
مرتبط باید از طریق یک
roles
روش رابطه در
User
مدل ایجاد شوند:
$user = User::factory() ->hasRoles(1, [ 'name' => 'Editor' ]) ->create();
روابط چند شکلی
روابط چند شکلی
نیز ممکن است با استفاده از کارخانه ها ایجاد شود.
روابط چند شکلی "morph many" به همان روشی ایجاد می شوند که روابط معمولی
"دارای بسیاری" هستند.
به عنوان مثال، اگر یک
App\Models\Post
مدل
morphMany
با یک
App\Models\Comment
مدل رابطه داشته باشد:
use App\Models\Post; $post = Post::factory()->hasComments(3)->create();
شکل به روابط
نمی توان از روش های جادویی برای ایجاد
morphTo
روابط استفاده کرد.
در عوض،
for
روش باید به طور مستقیم استفاده شود و نام رابطه باید به صراحت ارائه شود.
به عنوان مثال، تصور کنید که
Comment
مدل دارای
commentable
روشی است که یک
morphTo
رابطه را تعریف می کند.
for
در این شرایط، میتوانیم با استفاده از روش مستقیم،
سه نظر ایجاد کنیم که متعلق به یک پست است :
$comments = Comment::factory()->count(3)->for( Post::factory(), 'commentable')->create();
چند شکلی از بسیاری به بسیاری از روابط
روابط چند شکلی «بسیاری به بسیاری» (
morphToMany
/
morphedByMany
) ممکن است درست مانند روابط غیرچند شکلی «بسیاری از بسیاری» ایجاد شوند:
use App\Models\Tag;use App\Models\Video; $videos = Video::factory() ->hasAttached( Tag::factory()->count(3), ['public' => true] ) ->create();
البته،
has
روش جادویی نیز ممکن است برای ایجاد روابط چند شکلی "بسیاری به بسیاری"
استفاده شود:
$videos = Video::factory() ->hasTags(3, ['public' => true]) ->create();
تعریف روابط درون کارخانه ها
برای تعریف رابطه در کارخانه مدل خود، معمولاً یک نمونه کارخانه جدید را به
کلید خارجی رابطه اختصاص می دهید.
این معمولاً برای روابط "معکوس" مانند
belongsTo
و
morphTo
روابط انجام می شود.
به عنوان مثال، اگر می خواهید هنگام ایجاد یک پست یک کاربر جدید ایجاد کنید،
می توانید موارد زیر را انجام دهید:
use App\Models\User; /** * Define the model's default state. * * @return array */public function definition(){ return [ 'user_id' => User::factory(), 'title' => $this->faker->title(), 'content' => $this->faker->paragraph(), ];}
اگر ستونهای رابطه به کارخانهای بستگی دارد که آن را تعریف میکند، میتوانید یک بسته را به یک ویژگی اختصاص دهید. بسته شدن آرایه ویژگی ارزیابی شده کارخانه را دریافت می کند:
/** * Define the model's default state. * * @return array */public function definition(){ return [ 'user_id' => User::factory(), 'user_type' => function (array $attributes) { return User::find($attributes['user_id'])->type; }, 'title' => $this->faker->title(), 'content' => $this->faker->paragraph(), ];}
در حال اجرا بذرها
اگر میخواهید از
کاشتکنندههای پایگاه داده
برای پر کردن پایگاه داده خود در طول آزمایش ویژگی استفاده کنید، میتوانید
این
seed
روش را فراخوانی کنید.
بهطور پیشفرض، این
seed
متد، را اجرا میکند
DatabaseSeeder
، که باید همه بذرهای دیگر شما را اجرا کند.
از طرف دیگر، شما یک نام کلاس seeder خاص را به
seed
متد ارسال می کنید:
<?php namespace Tests\Feature; use Database\Seeders\OrderStatusSeeder;use Database\Seeders\TransactionStatusSeeder;use Illuminate\Foundation\Testing\RefreshDatabase;use Illuminate\Foundation\Testing\WithoutMiddleware;use Tests\TestCase; class ExampleTest extends TestCase{ use RefreshDatabase; /** * Test creating a new order. * * @return void */ public function test_orders_can_be_created() { // Run the DatabaseSeeder... $this->seed(); // Run a specific seeder... $this->seed(OrderStatusSeeder::class); // ... // Run an array of specific seeders... $this->seed([ OrderStatusSeeder::class, TransactionStatusSeeder::class, // ... ]); }}
از طرف دیگر، میتوانید به لاراول دستور دهید قبل از هر آزمایشی که از این
RefreshDatabase
ویژگی استفاده میکند، پایگاه داده را بهطور خودکار بذر کند.
شما می توانید این کار را با تعریف یک
$seed
ویژگی در کلاس تست پایه خود انجام دهید:
<?php namespace Tests; use Illuminate\Foundation\Testing\TestCase as BaseTestCase; abstract class TestCase extends BaseTestCase{ use CreatesApplication; /** * Indicates whether the default seeder should run before each test. * * @var bool */ protected $seed = true;}
زمانی که
$seed
ویژگی باشد
true
، تست
Database\Seeders\DatabaseSeeder
قبل از هر تستی که از این
RefreshDatabase
صفت استفاده می کند، کلاس را اجرا می کند.
با این حال، می توانید یک seder خاص را مشخص کنید که باید با تعریف یک
$seeder
ویژگی در کلاس آزمایشی خود اجرا شود:
use Database\Seeders\OrderStatusSeeder; /** * Run a specific seeder before each test. * * @var string */protected $seeder = OrderStatusSeeder::class;
ادعاهای موجود
لاراول چندین ادعای پایگاه داده را برای تست های ویژگی PHPUnit شما ارائه می دهد . در زیر به هر یک از این ادعاها خواهیم پرداخت.
assertDatabaseCount
ادعا کنید که یک جدول در پایگاه داده حاوی تعداد داده شده رکورد است:
$this->assertDatabaseCount('users', 5);
assertDatabaseHas
ادعا کنید که یک جدول در پایگاه داده حاوی رکوردهایی است که با قیود کلید/مقدار داده شده مطابقت دارند:
$this->assertDatabaseHas('users', [ 'email' => 'sally@example.com',]);
assertDatabase Missing
ادعا کنید که یک جدول در پایگاه داده حاوی رکوردهای منطبق با محدودیت های پرس و جو کلید / مقدار نیست:
$this->assertDatabaseMissing('users', [ 'email' => 'sally@example.com',]);
ادعا حذف شد
ادعا
assertDeleted
می کند که یک مدل Eloquent داده شده از پایگاه داده حذف شده است:
use App\Models\User; $user = User::find(1); $user->delete(); $this->assertDeleted($user);
این
assertSoftDeleted
روش ممکن است برای ادعای اینکه مدل Eloquent داده شده "نرم حذف شده" است
استفاده شود:
$this->assertSoftDeleted($user);
assertModelExists
ادعا کنید که یک مدل داده شده در پایگاه داده وجود دارد:
use App\Models\User; $user = User::factory()->create(); $this->assertModelExists($user);
assertModel Missing
ادعا کنید که یک مدل داده شده در پایگاه داده وجود ندارد:
use App\Models\User; $user = User::factory()->create(); $user->delete(); $this->assertModelMissing($user);