سؤال

أنا مقتنع في الغالب بفوائد اختبار الوحدة، وأود أن أبدأ في تطبيق المفهوم على رمز كبرى حالي كبير مكتوب في PHP. أقل من 10٪ من هذا الرمز موجه نحو الكائنات.

لقد بحثت في العديد من أطر اختبار الوحدات (phpunit، simpletest، & phpt). ومع ذلك، لم أجد أمثلة لأي من هذه التعليمات البرمجية الإجرائية. ما هو أفضل إطار لوضعي وهل هناك أي أمثلة لاختبار وحدة PHP باستخدام رمز غير OOP؟

هل كانت مفيدة؟

المحلول

يمكنك اختبار وحدة اختبار PHP، لا مشكلة. وكنت بالتأكيد ليس من الحظ إذا تم خلط رمزك مع HTML.

في مستوى اختبار التطبيق أو القبول، فإن PHP الإجرائي ربما يعتمد على قيمة Superglobals ($_POST, $_GET, $_COOKIE, ، إلخ.) لتحديد السلوك، وينتهي بما في ذلك ملف القالب وبصق الإخراج.

للقيام باختبار مستوى التطبيق، يمكنك فقط تعيين قيم Superglobal؛ بدء تشغيل المخزن المؤقت الإخراج (للحفاظ على مجموعة من HTML من الفيضانات الشاشة)؛ اتصل بالصفحة؛ تأكيد ضد الاشياء داخل المخزن المؤقت؛ وقمامة المخزن المؤقت في النهاية. لذلك، يمكنك أن تفعل شيئا مثل هذا:

public function setUp()
{
    if (isset($_POST['foo'])) {
        unset($_POST['foo']);
    }
}

public function testSomeKindOfAcceptanceTest()
{
    $_POST['foo'] = 'bar';
    ob_start();
    include('fileToTest.php');
    $output = ob_get_flush();
    $this->assertContains($someExpectedString, $output);
}

حتى بالنسبة إلى "الأطر" الهائلة مع الكثير من تشمل، فإن هذا النوع من الاختبارات سيخبرك إذا كان لديك ميزات المستوى على مستوى التطبيق يعمل أم لا. ستكون هذه مهمة حقا لأنك تبدأ في تحسين التعليمات البرمجية، لأنه حتى لو كنت مقتنعا بأن موصل قاعدة البيانات لا يزال يعمل ويبدو أفضل من ذي قبل، سترغب في النقر فوق زر ومعرفة ذلك، نعم، لا يزال بإمكانك ذلك تسجيل الدخول والخروج من خلال قاعدة البيانات.

عند مستويات أقل، هناك اختلافات بسيطة اعتمادا على نطاق متغير وعما إذا كانت الوظائف تعمل عن طريق الآثار الجانبية (إرجاع TRUE أو FALSE)، أو إرجاع النتيجة مباشرة.

هل تم تمرير المتغيرات بشكل صريح، كمعلمات أو صفائف من المعلمات بين الوظائف؟ أو هي المتغيرات المحددة في العديد من الأماكن المختلفة، وتم تمريرها ضمنيا مثل العالم؟ إذا كانت الحالة الصريحة (جيدة)، فيمكنك اختبار الوحدة وظيفة بواسطة (1) بما في ذلك الملف الذي يحمل الوظيفة، ثم (2) إطعام قيم اختبار الوظيفة مباشرة، و (3) التقاط الإخراج والتأكيد ضده. إذا كنت تستخدم Globals، فعليك أن تكون حذرا للغاية (على النحو الوارد أعلاه، في مثال $ _Post) لفظي جميع العالم بالكبراء بين الاختبارات. من المفيد أيضا أن تبقي الاختبارات صغيرة جدا (5-10 خطوط، 1-2 تأكيد) عند التعامل مع وظيفة يدفع وتسحب الكثير من العالم.

هناك مشكلة أساسية أخرى هي ما إذا كانت المهام تعمل عن طريق إرجاع الإخراج، أو عن طريق تغيير المعارف التي تم تمريرها، وإرجاع True / False بدلا من ذلك. في الحالة الأولى، يكون الاختبار أسهل، ولكن مرة أخرى، فمن الممكن في كلتا الحالتين:

// assuming you required the file of interest at the top of the test file
public function testShouldConcatenateTwoStringsAndReturnResult()
{
  $stringOne = 'foo';
  $stringTwo = 'bar';
  $expectedOutput = 'foobar';
  $output = myCustomCatFunction($stringOne, $stringTwo);
  $this->assertEquals($expectedOutput, $output);
}

في الحالة السيئة، حيث يعمل الكود الخاص بك عن طريق التأثيرات الجانبية وإرجاعه صحيحا أو خاطئا، لا يزال بإمكانك اختبار بسهولة:

/* suppose your cat function stupidly 
 * overwrites the first parameter
 * with the result of concatenation, 
 * as an admittedly contrived example 
 */
public function testShouldConcatenateTwoStringsAndReturnTrue()
    {
      $stringOne = 'foo';
      $stringTwo = 'bar';
      $expectedOutput = 'foobar';
      $output = myCustomCatFunction($stringOne, $stringTwo);
      $this->assertTrue($output);
      $this->Equals($expectedOutput, $stringOne);
    }

أتمنى أن يساعدك هذا.

نصائح أخرى

ما اختبارات الوحدة التي تقوم بها بشكل جيد، وما يجب عليك استخدامها من أجله، هو عندما يكون لديك جزء من التعليمات البرمجية التي تقدمها بعض عدد المدخلات، وتتوقع الحصول على عدد من المخرجات مرة أخرى. هذه الفكرة، عند إضافة وظائف في وقت لاحق، يمكنك تشغيل الاختبارات الخاصة بك والتأكد من أنها لا تزال تؤدي الوظيفة القديمة بنفس الطريقة.

لذلك، إذا كان لديك قاعدة رمز إجرائي، فيمكنك إنجاز هذا استدعاء وظائفك في طرق الاختبار

require 'my-libraries.php';
class SomeTest extends SomeBaseTestFromSomeFramework {
    public function testSetup() {
        $this->assertTrue(true);
    }

    public function testMyFunction() {
        $output = my_function('foo',3);

        $this->assertEquals('expected output',$output);
    }
}

هذه الخدعة مع قواعد كود PHP هي، غالبا ما تتداخل رمز المكتبة الخاص بك مع تشغيل إطار الاختبار الخاص بك، حيث سيكون لديك كودك وأطر الاختبار سيكون له عدد كبير من التعليمات البرمجية المتعلقة بإعداد بيئة تطبيق في مستعرض ويب (جلسة، مشتركة المتغيرات العالمية، إلخ). نتوقع أن تنفق في وقت ما من الوصول إلى نقطة حيث يمكنك تضمين رمز المكتبة الخاص بك وتشغيل اختبار بسيطة Dirt (وظيفة TestSetup أعلاه).

إذا لم يكن الرمز الخاص بك لا يحتوي على وظائف، فهل مجرد سلسلة من ملفات PHP التي تخرج صفحات HTML، فأنت من الحظ. لا يمكن فصل الكود الخاص بك إلى وحدات متميزة، مما يعني أن اختبار الوحدات لن يكون من استخدامك كثيرا. كنت أفضل حالا في قضاء وقتك في مستوى "اختبار القبول" مع منتجات مثل السيلينيوم و Watir.. وبعد سيتيح لك هذه تلقائيا تلقائيا، ثم تحقق من الصفحات للمحتوى كمواقع محددة / في نماذج.

يمكنك محاولة تضمين رمز غير OOP الخاص بك في فئة الاختبار باستخدام

require_once 'your_non_oop_file.php' # Contains fct_to_test()

ومع phpunit تحدد وظيفة الاختبار الخاصة بك:

testfct_to_test() {
   assertEquals( result_expected, fct_to_test(), 'Fail with fct_to_test' );
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top