اختبار الوحدة مع العناصر التي تحتاج إلى إرسال رؤوس

StackOverflow https://stackoverflow.com/questions/190292

  •  06-07-2019
  •  | 
  •  

سؤال

وأنا أعمل حاليا مع PHPUnit في محاولة لوضع اختبارات جنبا إلى جنب مع ما أنا أكتب، ولكن، أنا أعمل حاليا على كتابة مدير الدورة، وأواجه القضايا القيام بذلك ...

والمنشئ للفئة التعامل مع الدورة هو

private function __construct()
{
    if (!headers_sent())
    {
        session_start();
        self::$session_id = session_id();
    }
}

ولكن، وكما يرسل PHPUnit خارج النص قبل أن تبدأ الاختبار، أي اختبار على هذا الكائن بإرجاع تجربة فاشلة، كما تم إرسال "رؤوس" HTTP ...

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

المحلول

حسنا، هو كسر مدير جلسة العمل الخاصة بك في الأساس حسب التصميم. لتكون قادرة على اختبار شيء ما، يجب أن يكون من الممكن عزلها من الآثار الجانبية. لسوء الحظ، تم تصميم PHP في مثل هذه الطريقة، وأنه يشجع على استخدام الليبرالي للدولة العالمية (echo، header، exit، session_start الخ الخ).

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

إذا كنت لا تستطيع أن تفعل ذلك، لديك دائما الخيار كتابة اختبارات التكامل. على سبيل المثال. استخدام أي ما يعادل وPHPUnit من WebTestCase .

نصائح أخرى

وإنشاء ملف التمهيد لphpunit، الذي يدعو:

session_start();

وبعد ذلك تبدأ phpunit مثل هذا:

phpunit --bootstrap pathToBootstrap.php --anotherSwitch /your/test/path/

ويحصل على استدعاء ملف التمهيد قبل كل شيء آخر، لذلك لم يتم إرسال رأس وكل شيء يجب أن تعمل بشكل جيد.

وإخراج المطبوعات phpUnit كما الاختبارات بتشغيل بالتالي يسبب headers_sent () لإرجاع صحيح حتى في الاختبار الأول.

لتجاوز هذه المسألة لاختبار جناح كامل لكم ببساطة الحاجة الى استخدام ob_start () في البرنامج النصي الإعداد.

وعلى سبيل المثال، نقول لديك ملف باسم AllTests.php هذا هو أول شيء تحميلها من قبل phpUnit. هذا السيناريو قد تبدو كما يلي:

<?php

ob_start();

require_once 'YourFramework/AllTests.php';

class AllTests {
    public static function suite() {
        $suite = new PHPUnit_Framework_TestSuite('YourFramework');
        $suite->addTest(YourFramework_AllTests::suite());
        return $suite;
    }
}

وكان لي نفس المشكلة وأنا حلها عن طريق الاتصال phpunit مع العلم --stderr تماما مثل هذا:

phpunit --stderr /path/to/your/test

ونأمل أن يساعد شخص ما!

وأعتقد أن "الحق" الحل هو إنشاء فئة بسيطة جدا (بسيطة بحيث لا تحتاج لفحصها) وهذا هو المجمع للوظائف ذات الصلة جلسة PHP، وواستخدامه بدلا من استدعاء session_start()، الخ مباشرة .

في اختبار تمرير الكائن وهمية بدلا من جليل الحقيقي، والطبقة جلسة غير قابل للفحص.

private function __construct(SessionWrapper $wrapper)
{
   if (!$wrapper->headers_sent())
   {
      $wrapper->session_start();
      $this->session_id = $wrapper->session_id();
   }
}

وأنا أتساءل لماذا لا أحد الخيار XDebug وسرد:

/**
 * @runInSeparateProcess
 * @requires extension xdebug
 */
public function testGivenHeaderIsIncludedIntoResponse()
{
    $customHeaderName = 'foo';
    $customHeaderValue = 'bar';

    // Here execute the code which is supposed to set headers
    // ...

    $expectedHeader = $customHeaderName . ': ' . $customHeaderValue;
    $headers = xdebug_get_headers();

    $this->assertContains($expectedHeader, $headers);
}

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

وحتى إذا تم استخدام OB في مكان ما داخل الفصول الدراسية، فمن تكويم ويجب OB لا يؤثر ما يحدث في الداخل.

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

وإنشاء ملف التمهيد، وأشار إلى 4 مشاركة الرجوع يبدو أنظف سيلة للالتفاف حول هذا.

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

إذا كنت تحاول كتابة وحدة الاختبارات لوحدات التي تستخدم session_start أو setcookie طوال لهم، من بدء الجلسة في ملف boostrap يحصل جولة الخاص بك هذه القضايا.

وأما أنا unittesting بلدي التمهيد الآن (نعم أنا أعرف معظمكم لا تفعل ذلك)، أنا على التوالي في لنفس المشكلة (سواء رأس () وsession_start ()). الحل وجدت بسيطة إلى حد ما، في unittest بك التمهيد تعريف ثابت وببساطة التحقق من ذلك قبل إرسال رأس أو بدء الدورة:

// phpunit_bootstrap.php
define('UNITTEST_RUNNING', true);

// bootstrap.php (application bootstrap)
defined('UNITTEST_RUNNING') || define('UNITTEST_RUNNING', false);
.....
if(UNITTEST_RUNNING===false){
    session_start();
}

وأوافق على أن هذه ليست مثالية حسب التصميم، ولكن أنا unittesting أحد التطبيقات الموجودة، وإعادة كتابة أجزاء كبيرة ليس هو المطلوب. أنا أيضا باستخدام نفس المنطق لاختبار أساليب خاصة باستخدام __call () و__set () طرق سحرية.

public function __set($name, $value){
    if(UNITTEST_RUNNING===true){
       $name='_' . $name;
       $this->$name=$value;
    }
    throw new Exception('__set() can only be used when unittesting!');
 }

ويبدو أن تحتاج إلى ضخ الدورة بحيث يمكنك اختبار التعليمات البرمجية. الخيار الأفضل ولقد استخدمت هو Aura.Auth لعملية التوثيق واستخدام NullSession وNullSegment للاختبار.

اختبار النسمة مع جلسات فارغة

والإطار النسمة وجميل مكتوبة ويمكنك استخدام Aura.Auth من تلقاء نفسها من دون أي تبعيات إطار النسمة أخرى.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top