سؤال

في الصيف الماضي، كنت أقوم بتطوير تطبيق ASP.NET/SQL Server CRUD الأساسي، وكان اختبار الوحدة أحد المتطلبات.لقد واجهت بعض المشاكل عندما حاولت اختبار قاعدة البيانات.حسب فهمي، يجب أن تكون اختبارات الوحدة:

  • عديمي الجنسية
  • مستقلة عن بعضها البعض
  • قابلة للتكرار مع نفس النتائج أي.لا توجد تغييرات مستمرة

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

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

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

إذن، ماذا فعل مجتمع SO عندما واجه هذا الوضع؟


قال tgmdbm:

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

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

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

المحلول

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

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

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

نصائح أخرى

DBunit

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

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

وحيد القرن يسخر هو الذي يتمتع بسمعة جيدة.

نموك هو آخر.

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

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

في المكان الذي أعمل فيه، عادةً ما نصنع ملفاتنا الوهمية من الصفر، لكن هذا لا يعني أنه يتعين عليك القيام بذلك.

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

أنصح بشدة موك كإطار السخرية الخاص بك.لقد استخدمت Rhino Mocks وNMock.كان Moq بسيطًا جدًا وحل جميع المشكلات التي واجهتها مع الأطر الأخرى.

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

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

أنماط اختبار الوحدة

لقد شرحت الأسلوب الذي كنت أستخدمه في هذا الموقف بالذات هنا.

الفكرة الأساسية هي ممارسة كل أسلوب في DAL الخاص بك - تأكيد نتائجك - وعند اكتمال كل اختبار، قم بالتراجع بحيث تكون قاعدة البيانات الخاصة بك نظيفة (لا توجد بيانات غير هامة/اختبار).

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

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

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

    [TestFixture]
    public class TrannsactionScopeTests
    {
        private TransactionScope trans = null;

        [SetUp]
        public void SetUp()
        {
            trans = new TransactionScope(TransactionScopeOption.Required);
        }

        [TearDown]
        public void TearDown()
        {
            trans.Dispose();
        }

        [Test]
        public void TestServicedSameTransaction()
        {
            MySimpleClass c = new MySimpleClass();
            long id = c.InsertCategoryStandard("whatever");
            long id2 = c.InsertCategoryStandard("whatever");
            Console.WriteLine("Got id of " + id);
            Console.WriteLine("Got id of " + id2);
            Assert.AreNotEqual(id, id2);
        }
    }

إذا كنت تستخدم LINQ إلى SQL باعتباره ORM، فيمكنك إنشاء قاعدة البيانات بسرعة (شريطة أن يكون لديك حق وصول كافٍ من الحساب المستخدم لاختبار الوحدة).يرى http://www.aaron-powell.com/blog.aspx?id=1125

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