تساعد هذه الحزمة على تشغيل اختبارات الوحدة ذات الصلة بالوقت/الإدخال (على سبيل المثال، استدعاءات وظائف السكون، واستعلامات قاعدة البيانات، واستدعاءات واجهة برمجة التطبيقات، وما إلى ذلك) بشكل أسرع باستخدام Swoole.
تسمح وحدة الحزمة بإجراء اختبارات متعددة تتعلق بالوقت/الإدخال/الإخراج بشكل متزامن ضمن عملية PHP واحدة باستخدام Swoole. Counit متوافق مع PHPUnit مما يعني:
تبدو حالة الاختبار النموذجية للكونيت كما يلي:
use Deminy Counit TestCase ; // Here is the only change made for counit, comparing to test cases for PHPUnit.
class SleepTest extends TestCase
{
public function testSleep (): void
{
$ startTime = time ();
sleep ( 3 );
$ endTime = time ();
self :: assertEqualsWithDelta ( 3 , ( $ endTime - $ startTime ), 1 , ' The sleep() function call takes about 3 seconds to finish. ' );
}
}
بالمقارنة مع PHPUnit ، يمكن أن يجعل counit حالات الاختبار الخاصة بك أسرع. فيما يلي مقارنة عند تشغيل نفس مجموعة الاختبار باستخدام PHPUnit و counit لمشروع حقيقي. في مجموعة الاختبار، تقوم العديد من الاختبارات باستدعاء الطريقة DeminyCounitCounit::sleep() لانتظار حدوث شيء ما (على سبيل المثال، انتظار انتهاء صلاحية البيانات).
# من الاختبارات | # من التأكيدات | الوقت للانتهاء | |
---|---|---|---|
counit (بدون Swoole)، أو PHPUnit | 44 | 1148 | 9 دقائق و18 ثانية |
وحدة (مع تمكين Swoole) | 19 ثانية |
يمكن تثبيت الحزمة باستخدام Composer :
composer require deminy/counit --dev
أو، في ملف الملحن.json الخاص بك، تأكد من تضمين الحزمة deminy/counit :
{
"require-dev" : {
"deminy/counit" : " ~0.2.0 "
}
}
يحتوي المجلد ./tests/unit/global و ./tests/unit/case-by-case على بعض نماذج الاختبارات، حيث تتضمن الاختبارات المرتبطة بالوقت التالية:
لتشغيل نماذج الاختبارات، برجاء تشغيل حاويات Docker وتثبيت حزم Composer أولاً:
docker-compose up -d
docker compose exec -ti swoole composer install -n
هناك خمس حاويات بدأت: حاوية PHP، وحاوية Swoole، وحاوية Redis، وحاوية MySQL، وخادم الويب. لا تحتوي حاوية PHP على ملحق Swoole مثبتًا، بينما تحتوي حاوية Swoole على ملحق Swoole مثبتًا وممكّنًا.
كما ذكرنا سابقًا، يمكن كتابة حالات الاختبار بنفس الطريقة المستخدمة في PHPUnit . ومع ذلك، لتشغيل الاختبارات المتعلقة بالوقت/الإدخال/الإخراج بشكل أسرع باستخدام counit ، نحتاج إلى إجراء بعض التعديلات عند كتابة حالات الاختبار تلك؛ يمكن إجراء هذه التعديلات بأسلوبين مختلفين.
في هذا النمط، يتم تشغيل كل حالة اختبار في كوروتين منفصل تلقائيًا.
بالنسبة لحالات الاختبار المكتوبة بهذا النمط، فإن التغيير الوحيد الذي يجب إجراؤه على حالات الاختبار الموجودة لديك هو استخدام الفئة DeminyCounitTestCase بدلاً من PHPUnitFrameworkTestCase كفئة أساسية.
تبدو حالة الاختبار النموذجية للنمط العالمي كما يلي:
use Deminy Counit TestCase ; // Here is the only change made for counit, comparing to test cases for PHPUnit.
class SleepTest extends TestCase
{
public function testSleep (): void
{
$ startTime = time ();
sleep ( 3 );
$ endTime = time ();
self :: assertEqualsWithDelta ( 3 , ( $ endTime - $ startTime ), 1 , ' The sleep() function call takes about 3 seconds to finish. ' );
}
}
عند تحديد الطريقة المخصصة setUpBeforeClass() و teeDownAfterClass() في حالات الاختبار، يرجى التأكد من استدعاء الطرق الأصلية الخاصة بها وفقًا لهذه الطرق المخصصة.
يفترض هذا النمط عدم وجود تأكيدات فورية في حالات الاختبار، ولا تأكيدات قبل استدعاء دالة السكون () أو عملية الإدخال والإخراج (IO) الملائمة لـ coroutine. لا تزال حالات الاختبار مثل المتابعة تعمل، ولكنها ستؤدي إلى ظهور بعض رسائل التحذير عند اختبارها:
class GlobalTest extends Deminy Counit TestCase
{
public function testAssertionSuppression (): void
{
self :: assertTrue ( true , ' Trigger an immediate assertion. ' );
// ......
}
}
يمكننا إعادة كتابة فئة الاختبار هذه باستخدام أسلوب "كل حالة على حدة" (الذي سيتم مناقشته في القسم التالي) لإزالة رسائل التحذير.
للعثور على المزيد من الاختبارات المكتوبة بهذا النمط، يرجى التحقق من الاختبارات ضمن المجلد ./tests/unit/global (مجموعة الاختبار "global").
في هذا النمط، يمكنك إجراء تغييرات مباشرة على حالة الاختبار لجعلها تعمل بشكل غير متزامن.
بالنسبة لحالات الاختبار المكتوبة بهذا النمط، نحتاج إلى استخدام فئة DeminyCounitCounit وفقًا لذلك في حالات الاختبار التي نحتاج فيها إلى انتظار تنفيذ PHP أو إجراء عمليات الإدخال والإخراج. عادة، سيتم استخدام استدعاءات الطريقة التالية:
تبدو حالة الاختبار النموذجية لنمط كل حالة على حدة كما يلي:
use Deminy Counit Counit ;
use PHPUnit Framework TestCase ;
class SleepTest extends TestCase
{
public function testSleep (): void
{
Counit:: create ( function () { // To create a new coroutine manually to run the test case.
$ startTime = time ();
Counit:: sleep ( 3 ); // Call this method instead of PHP function sleep().
$ endTime = time ();
self :: assertEqualsWithDelta ( 3 , ( $ endTime - $ startTime ), 1 , ' The sleep() function call takes about 3 seconds to finish. ' );
});
}
}
في حال كنت بحاجة إلى منع رسالة التحذير "لم يقم هذا الاختبار بأي تأكيدات" أو لمطابقة عدد التأكيدات، يمكنك تضمين معلمة ثانية عند إنشاء coroutine الجديد:
use Deminy Counit Counit ;
use PHPUnit Framework TestCase ;
class SleepTest extends TestCase
{
public function testSleep (): void
{
Counit:: create ( // To create a new coroutine manually to run the test case.
function () {
$ startTime = time ();
Counit:: sleep ( 3 ); // Call this method instead of PHP function sleep().
$ endTime = time ();
self :: assertEqualsWithDelta ( 3 , ( $ endTime - $ startTime ), 1 , ' The sleep() function call takes about 3 seconds to finish. ' );
},
1 // Optional. To suppress warning message "This test did not perform any assertions", and to make the counters match.
);
}
}
للعثور على المزيد من الاختبارات المكتوبة بهذا النمط، يرجى التحقق من الاختبارات ضمن المجلد ./tests/unit/case-by-case (مجموعة الاختبار "كل حالة على حدة").
سنقوم هنا بإجراء الاختبارات في بيئات مختلفة، مع Swoole أو بدونه.
#1
قم بتشغيل مجموعات الاختبار باستخدام PHPUnit :
# To run test suite "global":
docker compose exec -ti php ./vendor/bin/phpunit --testsuite global
# or,
docker compose exec -ti swoole ./vendor/bin/phpunit --testsuite global
# To run test suite "case-by-case":
docker compose exec -ti php ./vendor/bin/phpunit --testsuite case-by-case
# or,
docker compose exec -ti swoole ./vendor/bin/phpunit --testsuite case-by-case
#2
قم بتشغيل مجموعات الاختبار باستخدام counit (بدون Swoole):
# To run test suite "global":
docker compose exec -ti php ./counit --testsuite global
# To run test suite "case-by-case":
docker compose exec -ti php ./counit --testsuite case-by-case
#3
قم بتشغيل مجموعات الاختبار باستخدام counit (مع تمكين الامتداد Swoole):
# To run test suite "global":
docker compose exec -ti swoole ./counit --testsuite global
# To run test suite "case-by-case":
docker compose exec -ti swoole ./counit --testsuite case-by-case
تستغرق أول مجموعتين من الأوامر نفس الوقت تقريبًا للانتهاء. تستخدم المجموعة الأخيرة من الأوامر counit وتعمل في حاوية Swoole (حيث يتم تمكين ملحق Swoole)؛ وبالتالي فهو أسرع من الآخرين:
أسلوب | # من الاختبارات | # من التأكيدات | الوقت للانتهاء | |
---|---|---|---|---|
counit (بدون Swoole)، أو PHPUnit | عالمي | 16 | 24 | 48 ثانية |
حالة على حدة | 48 ثانية | |||
وحدة (مع تمكين Swoole) | عالمي | 7 ثواني | ||
حالة على حدة | 7 ثواني |
وبما أن هذه الحزمة تسمح بإجراء اختبارات متعددة في وقت واحد، فلا ينبغي لنا استخدام نفس الموارد في اختبارات مختلفة؛ وإلا فقد تحدث ظروف السباق. على سبيل المثال، إذا كانت الاختبارات المتعددة تستخدم نفس مفتاح Redis، فقد يفشل بعضها في بعض الأحيان. في هذه الحالة، يجب علينا استخدام مفاتيح Redis مختلفة في حالات اختبار مختلفة. يمكن استخدام الأسلوب DeminyCounitHelper::getNewKey() و DeminyCounitHelper::getNewKeys() لإنشاء مفاتيح اختبار عشوائية وفريدة من نوعها.
تعمل الحزمة بشكل أفضل مع الاختبارات التي تستخدم وظيفة استدعاء السكون () ؛ يمكن أن يساعد أيضًا في تشغيل بعض الاختبارات المتعلقة بالإدخال/الإخراج بشكل أسرع، مع تطبيق القيود. فيما يلي قائمة بقيود هذه الحزمة:
هناك صور معدة مسبقًا لـ deminy/counit لتشغيل اختبارات العينات. فيما يلي أوامر إنشاء الصور:
docker build -t deminy/counit:php-only -f ./dockerfiles/php/Dockerfile .
docker build -t deminy/counit:swoole-enabled -f ./dockerfiles/swoole/Dockerfile .
تسمح هذه الحزمة باستخدام Swoole لتشغيل اختبارات متعددة متعلقة بالوقت/الإدخال والإخراج دون معالجة متعددة، مما يعني أنه يمكن تشغيل جميع الاختبارات ضمن عملية PHP واحدة. لفهم كيفية عملها بالضبط، أوصي بمراجعة هذه المحادثة المجانية عبر الإنترنت: برمجة CSP بلغة PHP (وهنا الشرائح).
في نظام PHP البيئي، هناك خيارات أخرى لتشغيل اختبارات الوحدة بالتوازي، وينتهي معظمها باستخدام المعالجة المتعددة:
رخصة معهد ماساتشوستس للتكنولوجيا.