ابدأ اختبار PHP الخاص بك باستخدام Codeception
نشرت: 2022-03-11قبل الانتقال إلى Codeception و PHP ، يجب أن نغطي الأساسيات ونبدأ بشرح سبب حاجتنا للاختبار في التطبيقات في المقام الأول. ربما يمكننا إكمال مشروع دون إضاعة الوقت في الاختبارات ، على الأقل هذه المرة؟
بالتأكيد ، لست بحاجة إلى اختبارات لكل شيء ؛ على سبيل المثال ، عندما تريد إنشاء صفحة رئيسية أخرى. ربما لا تحتاج إلى اختبارات عندما يحتوي مشروعك على صفحات ثابتة مرتبطة بجهاز توجيه واحد.
ومع ذلك ، فأنت بالتأكيد بحاجة إلى الاختبار عندما:
- يستخدم فريقك BDD / TDD.
- يحتوي Git repo الخاص بك على أكثر من التزامين.
- أنت محترف مناسب وتعمل في مشروع جاد.
يمكنك أن تبرر نفسك بالقول إن لديك بالفعل قسمًا مخصصًا للاختبار ، ومجموعة من الأشخاص الذين يجرون الاختبارات ويكتبون اختبارات جديدة عند الحاجة. ولكن ، هل يمكنك تخيل المدة التي سيستغرقها إصلاح الأخطاء بعد إضافة وظائف جديدة إلى مشروعك؟
ماذا يحل الاختبار؟
أولاً ، دعنا نقرر نوع المشكلات التي يمكن حلها من خلال الاختبار. لا يمكنك التخلص من جميع أخطائك في الاختبار ، ولكن يمكنك وصف السلوك المتوقع في حالات الاختبار. قد تكون الأخطاء داخل حالات الاختبار الخاصة بك. يظل كود السباغيتي رمز السباغيتي حتى عند استخدام حالات الاختبار.
ومع ذلك ، يمكنك التأكد من أنه سيتم تغيير شفرتك بعد ذلك (عن طريق إصلاح الأخطاء أو إضافة ميزات جديدة) ، بحيث تظل شفرتك خالية من الأخطاء الموضحة في الاختبار. إلى جانب ذلك ، يمكن استخدام الاختبارات المكتوبة جيدًا في بعض الأحيان في التوثيق لأنه يمكنك رؤية كيفية ظهور السيناريوهات النموذجية والتحقق من السلوك المتوقع. يمكننا القول أن الاختبار هو استثمار صغير ولكنه حاسم في المستقبل.
إذن ما نوع الاختبارات التي يمكننا إجراؤها؟
- اختبارات الوحدة: اختبارات منخفضة المستوى تتحقق من أجزاء صغيرة من التعليمات البرمجية الخاصة بك - طرق فصلك معزولة عن تعليمات برمجية أخرى.
- الاختبار التكاملي: تتحقق الاختبارات التكاملية من جزء من تطبيقك ، وقد تحتوي على عدة فئات أو طرق ، ولكن يجب أن تقتصر على ميزة واحدة. يجب أن يتحقق هذا الاختبار أيضًا من كيفية تفاعل الفئات المختلفة.
- الاختبار الوظيفي: يختبر طلبات معينة لتطبيقك: استجابة المتصفح ، وتغييرات قاعدة البيانات وما إلى ذلك.
- اختبار القبول: في معظم الحالات ، يعني اختبار القبول التحقق مما إذا كان التطبيق يلبي جميع متطلبات العميل.
للتوضيح ، لنفترض أننا قمنا بتوضيح العملية بشيء ملموس ، مثل المبنى. يتكون المبنى من كتل صغيرة تشكل الجدران. يجب أن يلبي كل لبنة المتطلبات المحددة ؛ يجب أن تتحمل الحمل المطلوب ، وأن يكون لها حجم وشكل محدد ، وما إلى ذلك. هذه اختبارات الوحدة. تتمثل فكرة الاختبارات التكاملية في التحقق من مدى إحكام ودقة التصاق الطوب مع بعضها البعض ، وكيف يتم دمجها في عنصر معين من المبنى. يمكن تشبيه الاختبارات الوظيفية بالاختبارات على جدار واحد للمبنى ، للتحقق مما إذا كان الجزء الداخلي محميًا من العناصر أم لا ، وما إذا كان من الممكن رؤية الشمس من خلال النافذة أم لا. يتضمن اختبار القبول اختبار المبنى بأكمله كمنتج كامل: افتح الباب ، وادخل إلى الداخل ، وأغلق الباب ، وشغل الضوء ، وصعد إلى الطابق الثاني وألق نظرة على الحديقة خارج المبنى.
تلبية الترميز
ومع ذلك ، فإن هذا التقسيم مشروط ويصعب أحيانًا مقاومة إغراء خلط أنواع مختلفة من الاختبارات.
يستخدم العديد من المطورين اختبارات الوحدة ويدعون أنها كافية. اعتدت أن أكون أحد هؤلاء المطورين. لقد وجدت أن استخدام أنظمة مختلفة لأنواع مختلفة من الاختبارات أمر صعب للغاية ويستغرق وقتًا طويلاً. منذ فترة ، قررت أن أجد شيئًا أكثر فائدة من PHPUnit ؛ أردت أن أكون أفضل في اختبار الكود الخاص بي ، لكنني لم أرغب في قراءة وتعلم الكثير من الوثائق والبحث عن المزالق. هكذا اكتشفت Codeception. في البداية ، كنت متشككًا ، كما هو الحال غالبًا عندما يتعلق الأمر بشيء جديد (هذا المشروع عمره خمس سنوات ، لذلك من الناحية الفنية ، لا يمكن اعتباره "جديدًا") ، ولكن بعد التلاعب به لبضعة أيام ، استنتجت أن Codeception نظام مفيد وقوي للغاية.
فكيف تقوم بتثبيت Codeception؟ الأمر بسيط بقدر ما يحصل:
$ composer require "codeception/codeception" $ php vendor/bin/codecept bootstrap
بعد التثبيت ، ستجد مجلدًا جديدًا باسم الاختبارات في مشروعك ، وستكون هناك بعض المجلدات الفرعية تسمى القبول والوحدة والوحدة . يبدو أنه يمكننا البدء في كتابة اختباراتنا. رائع ، لكن ماذا بعد؟
الآن ، حاول إضافة اختبار Hello World ذو القبول القياسي.
$ php vendor/bin/codecept generate:cept acceptance HelloWorld
الآن ، نحصل على ملف اختبار القبول / القبول / HelloWorldCept.php ، بالمحتوى التالي:
<?php $I = new AcceptanceTester($scenario); $I->wantTo('perform actions and see result');
المتغير الافتراضي ، المسمى $I
، ليس مجرد حرف ؛ إنها شخصية. ما الذي يجري الاختبارات؟ من الواضح أن المختبر. يفتح هذا المختبر صفحة موقع الويب الخاص بك أو صفه ، ويفعل شيئًا به ، ويظهر لك النتيجة النهائية لأفعاله. سترى ما الذي نجح وما الخطأ الذي حدث. لهذا السبب تم تسمية هذا الكائن باسم $I
ولماذا يحتوي على عمليات تسمى wantTo()
، see()
أو amOnPage()
.
لذلك ، دعنا نفكر كما يفعل المختبِر حول طرق التحقق من قابلية تشغيل الصفحة. الطريقة الأولى هي فتح الصفحة والبحث عن عبارة. يثبت أن الصفحة متاحة للزوار.
يجب أن يكون هذا سهلاً:
<?php $I->amOnPage('/'); $I->see('Welcome');
يمكننا استخدام هذا الأمر لإجراء اختبارات Codeception:
$ php vendor/bin/codecept run
نرى على الفور أن هناك شيئًا ما خطأ. للوهلة الأولى ، يبدو أن الرسالة طويلة جدًا وغير واضحة ، ولكن عندما ننظر عن كثب ، يصبح كل شيء واضحًا.
كان لدينا اختبار قبول واحد واكتشف خطأ:
Acceptance Tests (1) Perform actions and see result (HelloWorldCept) Error ---------- 1) Failed to perform actions and see result in HelloWorldCept (tests/acceptance/HelloWorldCept .php) [GuzzleHttp\Exception\ConnectException] cURL error 6: Could not resolve host: localhost (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)
هذا هو الجاني: المضيف المحلي غير متوفر.
وإليك خطوات السيناريو للاختبار لدينا:
1. $I->amOnPage("/")
حسنًا ، لنفتح الاختبارات / Accept.suite.yml url: http://localhost/
إلى شيء متاح بالفعل. في حالتي ، إنه مضيف الاختبار المحلي الخاص بي ، url: https://local.codeception-article.com/
قم بإجراء الاختبار مرة أخرى وهذا ما يجب أن ينتهي بك الأمر:
Acceptance Tests (1) --------------------------------------------------------------------------------------- Perform actions and result (HelloWorldCept) Ok
الصيحة! أول اختبار ناجح لنا!
بالطبع ، amOnPage()
ليست طريقة الاختبار الوحيدة المتاحة ، لقد اخترناها على سبيل المثال. يمكن تقسيم جميع طرق اختبار التشفير إلى المجموعات التالية:
- التفاعل مع الصفحة:
fillField()
،selectOption()
،submitForm()
،click()
- التأكيدات.
see()
،dontSee()
،seeElement()
،seeInCurrentUrl()
،seeCheckboxIsChecked()
،seeInField()
،seeLink()
. لجميع هذه الطرق ، يمكنك إضافة لاحقة واستخدامها عندما تحتاج إلى طريقة لا تقاطع سيناريو الاختبار عندما يتعذر العثور على شيء ما. - طرق ملفات تعريف الارتباط:
setCookie()
،grabCookie()
،seeCookie()
- التعليق ووصف سيناريوهات الاختبار:
amGoingTo()
،wantTo()
،expect()
. استخدم هذه الأساليب للحصول على اختبارات موصوفة وتعليقات جيدة ، مما سيساعدك على تذكر أهداف الاختبار.
لذلك ، إذا أردنا اختبار صفحة البريد الإلكتروني الخاصة بإعادة تعيين كلمة المرور ، فيمكننا القيام بذلك بهذه الطريقة:
<?php $I = new AcceptanceTester($scenario); $I->wantTo('Test forgotten password functionality'); $I->amOnPage('/forgotten') $I->see('Enter email'); $I->fillField('email', '[email protected]'); $I->click('Continue'); $I->expect('Reset password link not sent for incorrect email'); $I->see('Email is incorrect, try again'); $I->amGoingTo('Fill correct email and get link'); $I->see('Enter email'); $I->fillField('email', '[email protected]'); $I->click('Continue'); $I->expect('Reset password link sent for correct email'); $I->see('Please check your email for next instructions');
يبدو أن هذا يجب أن يفعل ذلك ، ولكن ماذا لو كانت هناك بعض الأجزاء المحملة على Ajax على الصفحة؟ هل يمكننا اختبار صفحة من هذا القبيل؟ الإجابة هي أن Codeception يستخدم PhpBrowser ، استنادًا إلى Symfony BrowserKit و Guzzle افتراضيًا. إنه بسيط وسريع وتحتاج فقط إلى تجعيد لاستخدامه.

يمكنك أيضًا استخدام السيلينيوم وصفحات الاختبار باستخدام متصفحات حقيقية. نعم ، سيكون أبطأ ، لكنك ستتمكن من اختبار JavaScript أيضًا.
أولاً ، تحتاج إلى تثبيت برنامج تشغيل السيلينيوم وتغيير Acceptance.yml وإعادة بناء فئة AcceptanceTester. بعد ذلك ، يمكنك استخدام التابعين wait()
و waitForElement()
. والأكثر إثارة للاهتمام ، أنك ستتمكن من توفير وقتك ومواردك باستخدام الطريقتين saveSessionSnapshot()
و loadSessionSnapshot()
. تتيح لك هذه الطريقة تخزين حالة الجلسة وبدء اختبارات جديدة في الجلسات السابقة. هذا مفيد في بعض المواقف ، على سبيل المثال ، في عملية ترخيص الاختبار.
لذلك ، ننتهي بقدرة بسيطة ، لكنها قوية ، لاختبار العديد من الوظائف.
الاختبار الوظيفي
حسنًا ، حان الوقت للانتقال إلى الاختبار الوظيفي.
$ php vendor/bin/codecept generate:cept functional HelloWorld
وهذا ما حصلنا عليه:
<?php $I = new FunctionalTester($scenario); $I->amOnPage('/'); $I->see('Welcome');
انتظر ماذا؟
لا ، هذا ليس خطأ. يجب كتابة الاختبارات الوظيفية بنفس طريقة الاختبارات التكاملية. الفرق هو أن الاختبارات الوظيفية تتفاعل مباشرة مع تطبيقك. هذا يعني أنك لست بحاجة إلى خادم ويب لإجراء اختبار وظيفي ، ولديك سعة أكبر لاختبار أجزاء مختلفة من تطبيقك.
هذا يعني أن الدعم لجميع الأطر غير موجود ، لكن قائمة الأطر المدعومة واسعة النطاق: Symfony ، Silex ، Phalcon ، Yii ، Zend Framework ، Lumen ، Laravel. يجب أن يكون هذا كافيا لمعظم الحالات ومعظم المطورين. يرجى الرجوع إلى وثائق الوحدة النمطية الخاصة بـ Codeception للحصول على قائمة بالوظائف المتاحة ، ثم قم بتشغيلها في functional.suite.yml
.
قبل أن ننتقل إلى اختبار الوحدة ، اسمح لي بإجراء انحراف بسيط. كما لاحظت ، فقد أنشأنا اختباراتنا باستخدام cept الرئيسي:
$ php vendor/bin/codecept generate: cept acceptance HelloWorld
هذه ليست الطريقة الوحيدة لإنشاء الاختبارات. هناك أيضًا اختبارات القسطرة . الفرق هو أنه يمكنك هيكلة سيناريوهات متعددة ذات صلة في فئة واحدة:
$ php vendor/bin/codecept generate:cest acceptance HelloWorld <?php class HelloWorldCest { public function _before(AcceptanceTester $I) { $I->amOnPage('/forgotten') } public function _after(AcceptanceTester $I) { } // tests public function testEmailField(AcceptanceTester $I) { $I->see('Enter email'); } public function testIncorrectEmail(AcceptanceTester $I) { $I->fillField('email', '[email protected]'); $I->click('Continue'); $I->see('Email is incorrect, try again'); } public function testCorrectEmail(AcceptanceTester $I) { $I->fillField('email', '[email protected]'); $I->click('Continue'); $I->see('Please check your email for next instructions'); } }
في هذا المثال ، يتم تشغيل الطريقتين _before()
و _after()
قبل وبعد كل اختبار. يتم تمرير مثيل من فئة AcceptanceTester
إلى كل اختبار ، بحيث يمكنك استخدامه بنفس الطريقة كما في اختبارات cest. يمكن أن يكون هذا النمط من الاختبارات مفيدًا في مواقف معينة ، لذلك يجدر بنا أن نأخذ في الاعتبار.
وحدة التجارب
حان الوقت لبعض اختبارات الوحدة.
يعتمد برنامج الترميز على PHPUnit ، لذا يمكنك استخدام الاختبارات المكتوبة لـ PHPUnit. لإضافة اختبارات PHPUnit جديدة ، استخدم الطريقة التالية:
$ php vendor/bin/codecept generate:phpunit unit HelloWorld
أو مجرد اكتساب الاختبارات الخاصة بك على \PHPUnit_Framework_TestCase
.
ولكن إذا كنت تريد شيئًا أكثر ، فعليك تجربة اختبارات وحدة Codeception:
$ php vendor/bin/codecept generate:test unit HelloWorld <?php class HelloWorldTest extends \Codeception\TestCase\Test { /** * @var \UnitTester */ protected $tester; protected function _before() { } protected function _after() { } // tests public function testUserSave() { $user = User::find(1); $user->setEmail('[email protected]'); $user->save(); $user = User::find(1); $this->assertEquals('[email protected]', $user->getEmail()); } }
لا شيء غير عادي الآن. الطرق _before()
و _after()
هي setUp()
و tearDown()
نظائرها وسيتم تشغيلها قبل وبعد كل اختبار.
الميزة الرئيسية لهذا الاختبار هي قدرته على تمديد عملية الاختبار الخاصة بك من خلال تضمين الوحدات التي يمكن تشغيلها في unit.suite.yml
:
- الوصول إلى memcache وقواعد البيانات لتتبع التغييرات (يدعم MySQL و SQLite و PostgreSQL و MongoDB)
- اختبار تطبيقات REST / SOAP
- قوائم الانتظار
كل وحدة لها ميزاتها الخاصة ، لذلك من الأفضل التحقق من الوثائق وجمع المعلومات اللازمة لكل وحدة قبل الشروع في الاختبارات الفعلية.
بالإضافة إلى ذلك ، يمكنك استخدام حزمة Codeception / Specify (التي يجب إضافتها إلى composer.json
) وكتابة وصف مثل:
<?php class HelloWorldTest extends \Codeception\TestCase\Test { use \Codeception\Specify; private $user; protected function _before() { $this->user = User::find(1); } public function testUserEmailSave() { $this->specify("email can be stored", function() { $this->user->setEmail('[email protected]'); $this->user->save(); $user = User::find(1); $this->assertEquals('[email protected]', $user->getEmail()); }); } }
كود PHP داخل وظائف الإغلاق هذه معزول ، لذا فإن التغييرات الداخلية لن تؤثر على بقية التعليمات البرمجية الخاصة بك. ستساعدك الأوصاف على جعل الاختبار أكثر قابلية للقراءة وتسهيل تحديد الاختبارات الفاشلة.
كإضافة اختيارية ، يمكنك استخدام حزمة Codeception\Verify
لبناء جملة تشبه BDD:
<?php public function testUserEmailSave() { verify($map->getEmail())->equals('[email protected]'); }
وبالطبع يمكنك استخدام بذرة:
<?php public function testUserEmailSave() { $user = Stub::make('User', ['getEmail' => '[email protected]']); $this->assertEquals('[email protected]', $user->getEmail()); }
الحكم: التشفير يوفر الوقت والجهد
إذن ما الذي يجب أن تتوقعه من Codeception؟ لمن هذا؟ هل هناك أي محاذير؟
في رأيي ، يعتبر إطار عمل الاختبار هذا مناسبًا لجميع أنواع الفرق المختلفة: كبيرها وصغيرها ، محترف PHP مبتدئ ومتخصص في المعركة ، أولئك الذين يستخدمون إطار عمل شائعًا ، وأولئك الذين لا يستخدمون أي إطار عمل.
على أي حال ، كل هذا يتلخص في: Codeception جاهز لوقت الذروة.
إنه إطار عمل ناضج وموثق جيدًا يمكن توسيعه بسهولة من خلال العديد من الوحدات. يعد برنامج Codeception حديثًا ، ولكنه يعتمد على PHPUnit التي تم اختبارها بمرور الوقت ، والتي يجب أن تطمئن المطورين الذين لا يرغبون في تجربة الكثير.
إنه يعمل بشكل جيد ، مما يعني أنه سريع ولا يتطلب الكثير من الوقت والجهد. والأفضل من ذلك ، أنه من السهل نسبيًا إتقانه ، ويجب أن تساعد الوثائق الوفيرة في عملية تعلم خالية من المتاعب.
من السهل أيضًا تثبيت وتهيئة Codeception ، ومع ذلك فهو يضم الكثير من الخيارات المتقدمة. في حين أن معظم المستخدمين لن يحتاجوا جميعًا (أو في الواقع معظمهم) ، كل هذا يتوقف على ما تنوي فعله به. يمكنك البدء بالأساسيات ، وستكون الميزات الإضافية مفيدة عاجلاً أم آجلاً.