اختبارات قواعد البيانات في Laravel
مقدمة
يزوّدك Laravel بمجموعة من الأدوات المفيدة لتسهيل اختبار تطبيقاتك المقادة بواسطة قواعد البيانات. أولاً، يمكنك استخدام التابع المساعد assertDatabaseHas
للتأكد من أن البيانات موجودة ضمن قاعدة البيانات ضمن مجموعة الشروط المعطاة. على سبيل المثال، إن أردت التأكد من أن سجلًا ما موجود ضمن جدول users
ببريد مطابق لـ sally@example.com
، يمكنك فعل التالي:
public function testDatabase()
{
// القيام بمناداة التطبيق...
$this->assertDatabaseHas('users', [
'email' => 'sally@example.com'
]);
}
يمكنك أيضًا استخدام المساعد assertDatabaseMissing
للتأكد من عدم وجود بيانات.
بالطبع، إن التابع assertDatabaseHas
والتوابع المساعدة الأخرى هي توابع وجدت لتسهيل أمورك. يمكنك استخدام أي تابع من توابع PHPUnit المضمّنة لاستكمال اختباراتك.
توليد المعامل Factories
لتوليد معمل، استخدم أمر artisan make:factory
:
php artisan make:factory PostFactory
سيوضع المعمل الجديد في المجلد database/factories
.
يمكن استخدام الخيار model--
للإشارة إلى اسم النموذج Model المنشئ بواسطة المعمل. سيعبّئ هذا الأمر مسبقًا المعمل بالنموذج المعطى:
php artisan make:factory PostFactory --model=Post
إعادة تعيين قاعدة البيانات بعد كل اختبار
من الضروري أن تعيد تعيين قاعدة بياناتك بعد كل اختبار حتى لا تتضارب البيانات المضافة من اختبار مسبق مع الاختبارات القادمة. تأخذ السمة (trait) RefreshDatabase
الحل الأمثل لتهجير قاعدة معطياتك بناءً على كونها قاعدة بيانات ذاكرية أو تقليدية. استخدم السمة على صنف الاختبار الخاص بك، وكل شيء سيعالج تلقائيًا:
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
class ExampleTest extends TestCase
{
use RefreshDatabase;
/**
* مثال بسيط عن اختبار فعال.
*
* @return void
*/
public function testBasicExample()
{
$response = $this->get('/');
// ...
}
}
كتابة المعامل Writing Factories
قد تحتاج عند الاختبار إلى إضافة بعض السجلات إلى قاعدة بياناتك قبل البدء. بدلًا من تعيين قيم كل حقل يدويًا عند إضافة سجلات الاختبار، يتيح Laravel تعريف مجموعة افتراضية من الخصائص لكلّ من نماذج Eloquent الخاصة بك، وذلك باستخدام معامل النماذج. للبدء، اطلع على الملف database/factories/UserFactory.php
في تطبيقك. بشكل افتراضي، يحتوي هذا الملف على تعريف معمل واحد:
use Faker\Generator as Faker;
$factory->define(App\User::class, function (Faker $faker) {
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret
'remember_token' => str_random(10),
];
});
يمكنك إعادة أي مجموعة افتراضية من القيم التي تريدها لنموذجك ضمن النطاق المغلق (Closure) الذي يعمل كتعريف للمعمل. يستقبل التعبير المغلق كائنًا من مكتبة Faker، التي تتيح توليد العديد من أنواع البيانات العشوائية.
يمكنك أيضًا إنشاء معامل إضافية لكل كائن على حدة لضمان تنظيم أفضل. على سبيل المثال، يمكنك إنشاء UserFactory.php
و CommentFactory.php
ضمن المجلد database/factories
. ستُحمّل جميع الملفات الموجودة ضمن المجلد factories
تلقائيًا من قبل Laravel.
ملاحظة: يمكنك تعيين الموقع locale الافتراضي لـ Faker بإضافة الخيار faker_locale
إلى ملف الضبط config/app.php
.
حالات المعامل
تمكّنك الحالات من تعريف التعديلات الممكن تطبيقها على معامل النماذج بأي صيغة ممكنة. على سبيل المثال، قد يحتوي نموذج User
على حالة delinquent
، التي تقوم بتعديل خاصية من خصائصه الافتراضية. يمكنك تعريف تحويلات الحالات الخاصة بك عن طريق التابع state
. من أجل الحالات البسيطة، يمكنك تمرير مصفوفة من التعديلات المطلوبة:
$factory->state(App\User::class, 'delinquent', [
'account_status' => 'delinquent',
]);
إذا تطلبت حالتك احتساب معين من كائن faker$
، يمكنك استخدام تعبير مغلق لاحتساب تعديلات الحالة:
$factory->state(App\User::class, 'address', function ($faker) {
return [
'address' => $faker->address,
];
});
دوال رد النداء للمعامل
تسجَّل دوال رد النداء للمعامل عن طريق التابعين afterMaking
و afterCreating
، وتمكنك من تنفيذ عمليات إضافية بعد إنشاء أو حفظ نموذج معين. على سبيل المثال، يمكنك استخدام هذه الدوال لربط النماذج الإضافية للنموذج المنشأ:
$factory->afterMaking(App\User::class, function ($user, $faker) {
// ...
});
$factory->afterCreating(App\User::class, function ($user, $faker) {
$user->accounts()->save(factory(App\Account::class)->make());
});
يمكنك أيضًا تعريف دوال رد نداء لحالات المعامل:
$factory->afterMakingState(App\User::class, 'delinquent', function ($user, $faker) {
// ...
});
$factory->afterCreatingState(App\User::class, 'delinquent', function ($user, $faker) {
// ...
});
استخدام المعامل
إنشاء النماذج
بعد تعريف المعامل الخاصة بك، يمكنك استخدام التابع العام factory
في اختباراتك أو في ملفات البذور (seeds) الخاصة بك لتوليد كائنات النماذج. لنطّلع على بعض الأمثلة عن إنشاء النماذج. أولاً، سنستخدم التابع make
لإنشاء النماذج دون حفظها في قاعدة البيانات:
public function testDatabase()
{
$user = factory(App\User::class)->make();
// استخدام النموذج بالاختبارات...
}
يمكنك أيضًا إنشاء مجموعة من عدة نماذج:
// إنشاء ثلاث كائنات من نوع مستخدم User...
$users = factory(App\User::class, 3)->make();
تعيين الحالات
يمكنك أيضًا تعيين أي من الحالات المعرفة لنماذجك. في حال أردت تعيين أكثر من حالة، مرّر اسم كل حالة تريد تعيينها:
$users = factory(App\User::class, 5)->states('delinquent')->make();
$users = factory(App\User::class, 5)->states('premium', 'delinquent')->make();
إعادة تعريف الخصائص
في حال أردت إعادة تعيين بعض الخصائص في نماذجك، مرّر مصفوفة قيم إلى التابع make
. ستُستبدل القيم الموجودة بالمعمل مع القيم الممررة، وستبقى القيم غير الممررة على حالها كما عُرّفت في المعمل:
$user = factory(App\User::class)->make([
'name' => 'Abigail',
]);
حفظ وضمان استمراريّة النماذج
ينشئ التابع create
ويحفظ النموذج إلى قاعدة البيانات وذلك باستخدام التابع save
الخاص بـ Eloquent:
public function testDatabase()
{
// إنشاء كائن مستخدم من نوع App\User وحيد..
$user = factory(App\User::class)->create();
// إنشاء ثلاثة كائنات مستخدمين من نوع App\User..
$users = factory(App\User::class, 3)->create();
// استخدام الكائنات في الاختبارات..
}
يمكنك أيضًا إعادة تعيين الخصائص المعرفة عن طريق تمرير مصفوفة إلى التابع create
:
$user = factory(App\User::class)->create([
'name' => 'Abigail',
]);
العلاقات
في هذا المثال، سنربط علاقة لبعض النماذج المنشأة. عند استخدام التابع create
لإنشاء عدة نماذج، ستُعاد مجموعة Eloquent تمكنك من استخدام أي من التوابع المزودة من المجموعة، كالتابع each
:
$users = factory(App\User::class, 3)
->create()
->each(function ($u) {
$u->posts()->save(factory(App\Post::class)->make());
});
العلاقات والتعابير المغلقة للخصائص
يمكنك أيضًا ربط العلاقات بالنماذج باستخدام تعابير مغلقة في تعاريف المعامل. على سبيل المثال، في حال أردت إنشاء كائن User
جديد عند إنشائك لكائن Post
، يمكنك فعل التالي:
$factory->define(App\Post::class, function ($faker) {
return [
'title' => $faker->title,
'content' => $faker->paragraph,
'user_id' => function () {
return factory(App\User::class)->create()->id;
}
];
});
تُمرّر مصفوفة من الخصائص المعالجة من المعمل إلى هذه التعابير المغلقة:
$factory->define(App\Post::class, function ($faker) {
return [
'title' => $faker->title,
'content' => $faker->paragraph,
'user_id' => function () {
return factory(App\User::class)->create()->id;
},
'user_type' => function (array $post) {
return App\User::find($post['user_id'])->type;
}
];
});
التوكيدات المتاحة
يتيح Laravel مجموعة من التوكيدات الخاصة بقواعد البيانات من أجل اختبارات PHPUnit الخاصة بك:
التابع | الشرح |
---|---|
$this->assertDatabaseHas($table, array $data);
|
التأكد من أن الجدول المعطى الموجود ضمن قاعدة البيانات يحتوي على البيانات المعطاة. |
$this->assertDatabaseMissing($table, array $data);
|
التأكد من أن الجدول المعطى الموجود ضمن قاعدة البيانات لا يحتوي على البيانات المعطاة. |
$this->assertSoftDeleted($table, array $data);
|
التأكد من أن السجل المعطى قد تم حذفه وهمياً. |