اختبار الوحدة مع الوظائف التي ترجع نتائج عشوائية

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

سؤال

لا أعتقد أن هذا يقتصر على لغة أو إطار عمل، لكنني أستخدم xUnit.net وC#.

لدي وظيفة تقوم بإرجاع تاريخ عشوائي في نطاق معين.لقد مررت بتاريخ، ويكون تاريخ العودة دائمًا في نطاق من 1 إلى 40 عامًا قبل التاريخ المحدد.

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

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

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

المحلول

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

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

ولقد كان لي مشكلة من قبل مع غير موحدة وظائف "عشوائية" .. يمكن أن يكون الألم الحقيقي، فإنه يستحق اختبار لفي وقت مبكر.

نصائح أخرى

وهمية أو وهمية من مولد رقم عشوائي

وتفعل شيئا مثل هذا ... لم أكن ترجمة عليه ذلك قد يكون هناك عدد قليل من أخطاء في بناء الجملة.

public interface IRandomGenerator
{
    double Generate(double max);
}

public class SomethingThatUsesRandom
{
    private readonly IRandomGenerator _generator;

    private class DefaultRandom : IRandomGenerator
    {
        public double Generate(double max)
        {
            return (new Random()).Next(max);
        }
    }

    public SomethingThatUsesRandom(IRandomGenerator generator)
    {
        _generator = generator;
    }

    public SomethingThatUsesRandom() : this(new DefaultRandom())
    {}

    public double MethodThatUsesRandom()
    {
        return _generator.Generate(40.0);
    }
}

في اختبار الخاص بك، فقط وهمية أو وهمية خارج IRandomGenerator للعودة شيء المعلبة.

وأعتقد أن هناك ثلاثة جوانب مختلفة من هذه المشكلة التي يمكنك اختبار.

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

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

والثلث: تم تنفيذ بلدي خوارزمية العمل؟ وهذا هو، نظرا قائمة معروفة من المدخلات شبه عشوائي، هل هو إنتاج قائمة المتوقعة من التمور شبه عشوائي؟

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

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

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

وبشكل عادي وأنا استخدم بالضبط النهج المقترح الخاص بك: السيطرة على مولد عشوائي. تهيئة منه للاختبار مع البذور الافتراضي (أو يحل محله من قبل وكيل الأرقام التي تناسب testcases لي عودة)، وذلك لدي القطعية / السلوك قابلة للاختبار.

إذا كنت تريد التحقق من نوعية أرقام عشوائية (من حيث الاستقلال) وهناك عدة طرق للقيام بذلك. واحد وسيلة جيدة لل تشي اختبار مربع .

واعتمادا على كيفية يخلق الدالة تاريخ عشوائية، قد تحتاج أيضا للتأكد من مواعيد غير قانونية: سنة كبيسة مستحيلة، أو في اليوم ال31 من شهر لمدة 30 يوما

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

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

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

وأوصي تجاوز وظيفة عشوائية. أنا وحدة اختبار في PHP لذلك أنا أكتب هذا الرمز:

// If we are unit testing, then...
if (defined('UNIT_TESTING') && UNIT_TESTING)
{
   // ...make our my_rand() function deterministic to aid testing.
   function my_rand($min, $max)
   {
      return $GLOBALS['random_table'][$min][$max];
   }
}
else
{
   // ...else make our my_rand() function truly random.
   function my_rand($min = 0, $max = PHP_INT_MAX)
   {
      if ($max === PHP_INT_MAX)
      {
         $max = getrandmax();
      }
      return rand($min, $max);
   }
}

وبعد ذلك تعيين random_table كما تتطلب ذلك في الاختبار.

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

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

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