سؤال

أنا أبحث عن أداة يمكنها إجراء اختبار الوحدة، مثل

IPerson p = new Person();
p.Name = "Sklivvz";
Assert.AreEqual("Sklivvz", p.Name);

وإنشاء فئة كعب الروتين المقابلة والواجهة تلقائيًا

interface IPerson         // inferred from IPerson p = new Person();
{
    string Name 
    { 
        get;              // inferred from Assert.AreEqual("Sklivvz", p.Name);
        set;              // inferred from p.Name = "Sklivvz";
    }
}

class Person: IPerson     // inferred from IPerson p = new Person();
{
    private string name;  // inferred from p.Name = "Sklivvz";

    public string Name    // inferred from p.Name = "Sklivvz";
    {
        get
        {
            return name;  // inferred from Assert.AreEqual("Sklivvz", p.Name);
        }
        set
        {
            name = value; // inferred from p.Name = "Sklivvz";
        }
    }

    public Person()       // inferred from IPerson p = new Person();
    {
    }
}

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

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

المحلول

يبدو أن ما تحتاجه هو محلل للغتك (Java)، ومحلل للاسم والنوع.("منشئ جدول الرموز").

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

عادةً ما يشكو محلل الاسم/النوع عندما لا يتمكن من العثور على تعريف.ما تريد أن تفعله هو العثور على الشيء "غير المحدد" الذي يسبب المشكلة، واستنتاج نوع له.

ل

 IPerson p = new Person();

يعرف محلل الأسماء أنه لم يتم تعريف "الشخص" و"IPerson".لو كان

 Foo  p =  new Bar();

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

ل

 p.Name = "Sklivvz";

نظرًا لأن p يجب أن يكون واجهة (حسب الاستدلال السابق)، فيجب أن يكون الاسم عضوًا في الحقل، ويبدو أن نوعه هو سلسلة من المهمة.

ومع ذلك البيان:

 Assert.AreEqual("Sklivvz", p.Name);

يتم حل الأسماء والأنواع دون مشكلة أخرى.

إن محتوى كيانات IFoo وFoo متروك لك نوعًا ما؛لم يكن عليك استخدام get and set ولكن هذا ذوق شخصي.

لن يعمل هذا جيدًا عندما يكون لديك كيانات متعددة في نفس العبارة:

 x = p.a + p.b ;

نحن نعلم أن a وb هما حقلان محتملان، لكن لا يمكنك تخمين النوع الرقمي إذا كانا رقميين بالفعل، أو إذا كانا عبارة عن سلاسل (هذا قانوني بالنسبة للسلاسل في Java، لا أعرف عن C#).بالنسبة لـ C++، فإنك لا تعرف حتى معنى "+"؛قد يكون عامل تشغيل في فئة Bar.إذن ما عليك فعله هو التجميع قيود, ، على سبيل المثال، "a هو رقم أو سلسلة غير محددة"، وما إلى ذلك.وبينما تقوم الأداة بجمع الأدلة، فإنها تعمل على تضييق مجموعة القيود المحتملة.(هذا يعمل مثل تلك المسائل الكلامية:"جو لديه سبعة أبناء.جيف أطول من سام.لا يستطيع هاري الاختباء خلف سام....من هو توأم جيف؟" حيث عليك جمع الأدلة وإزالة المستحيلات).عليك أيضًا أن تقلق بشأن الحالة التي ينتهي بك الأمر فيها إلى التناقض.

يمكنك استبعاد حالة p.a+p.b، ولكن بعد ذلك لا يمكنك كتابة اختبارات الوحدة الخاصة بك مع الإفلات من العقاب.هناك حلول قياسية للقيود إذا كنت تريد الإفلات من العقاب.(يا له من مفهوم).

حسنًا، لدينا الأفكار، الآن، هل يمكن القيام بذلك بطريقة عملية؟

يتطلب الجزء الأول من هذا محللًا ومحللًا للاسم والنوع قابلاً للانحناء.أنت بحاجة إلى حل قيود أو على الأقل عملية "تدفقات القيمة المحددة إلى قيمة غير محددة" (حل قيود تافهة).

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

يوفر DMS آلية تحليل للأغراض العامة، ويمكنه إنشاء شجرة لأي واجهة أمامية يتم تقديمها له (على سبيل المثال، Java، وهناك واجهة أمامية C#).سبب اختياري لـ Java هو أن الواجهة الأمامية لـ Java لدينا تحتوي على كل آليات تحليل الأسماء والأنواع، ويتم توفيرها في نموذج مصدر بحيث يمكن ثنيها.إذا كنت متمسكًا بحل القيود التافهة، فمن المحتمل أن تتمكن من ثني محلل اسم Java لمعرفة الأنواع.سوف يتيح لك DMS تجميع الأشجار التي تتوافق مع أجزاء التعليمات البرمجية، ودمجها في أشجار أكبر؛عندما تقوم أداتك بجمع الحقائق لجدول الرموز، يمكنها بناء الأشجار البدائية.

في مكان ما، عليك أن تقرر أنك انتهيت.كم عدد اختبارات الوحدة التي يجب على الأداة رؤيتها قبل أن تعرف الواجهة بأكملها؟(أعتقد أنه يأكل كل ما تقدمه؟).بمجرد اكتماله، يقوم بتجميع الأجزاء الخاصة بالأعضاء المختلفين وبناء AST للواجهة؛يمكن لـ DMS استخدام الطابعة الجميلة الخاصة بها لتحويل AST مرة أخرى إلى كود المصدر كما أظهرت.

أقترح استخدام Java هنا لأن الواجهة الأمامية لـ Java لدينا تتمتع بدقة الاسم والنوع.الواجهة الأمامية لـ C# الخاصة بنا لا تفعل ذلك.هذه مجرد مسألة طموح.يجب على شخص ما أن يكتب واحدة، ولكن هذا يتطلب قدرًا كبيرًا من العمل (على الأقل كان ذلك لـ Java ولا أستطيع أن أتخيل أن لغة C# مختلفة حقًا).

لكن الفكرة تعمل بشكل جيد من حيث المبدأ باستخدام DMS.

يمكنك القيام بذلك باستخدام بعض البنية التحتية الأخرى التي أتاحت لك الوصول إلى محلل ومحلل اسم ونوع قابل للانحناء.قد لا يكون من السهل الحصول على لغة C#؛أظن أن MS قد يمنحك محللًا وإمكانية الوصول إلى دقة الاسم والنوع، ولكن ليس بأي طريقة لتغيير ذلك.ربما مونو هو الجواب؟

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

نصائح أخرى

إنه لأمر مدهش كيف لم يقدم أحد أي شيء حقًا تجاه ما كنت تطلبه.

لا أعرف الإجابة ولكن سأعطي رأيي فيها.

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

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

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

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

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

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

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

dynamic p = someFactory.Create("MyNamespace.Person");
p.Name = "Sklivvz";
Assert.AreEqual("Sklivvz", p.Name);

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

بعض السلبيات التي أراها:

  • تحتاج إلى تشغيل الكود في وضعين "، وهو أمر مزعج.
  • لكي يتمكن الوكيل من "رؤية" المكالمات وتسجيلها، يجب تنفيذها؛لذلك رمز في أ catch كتلة، على سبيل المثال، يجب أن تعمل.
  • يجب عليك تغيير الطريقة التي تنشئ بها الكائن قيد الاختبار.
  • عليك أن تستخدم dynamic;ستفقد أمان وقت الترجمة في عمليات التشغيل اللاحقة وسيحقق أداءً رائعًا.

الميزة الوحيدة التي أراها هي أنها كذلك أرخص كثيرا لإنشاء من محلل متخصص.

أنا أحب CodeRush من DevExpress.لديهم محرك قوالب ضخم قابل للتخصيص.والأفضل بالنسبة لي هو عدم وجود مربعات حوار.لديهم أيضًا وظيفة لإنشاء أساليب وواجهات وفئات من واجهة غير موجودة.

حاول إلقاء نظرة على Pex، وهو مشروع من Microsoft حول اختبار الوحدة، والذي لا يزال قيد البحث

Research.microsoft.com/en-us/projects/Pex/

أعتقد أن ما تبحث عنه هو مجموعة أدوات التشويش (https://en.wikipedia.org/wiki/Fuzz_testing).

رغم أنني لم أستخدمها مطلقًا، فقد تمنح Randoop.NET فرصة لإنشاء "اختبارات الوحدة" http://randoop.codeplex.com/

يأتي Visual Studio مع بعض الميزات التي يمكن أن تكون مفيدة لك هنا:

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

إذا كنت من مستخدمي لوحة المفاتيح (وأنا كذلك)، فبعد كتابة القوسين المغلقين مباشرة، يمكنك القيام بما يلي:

  • كنترول-. (لفتح العلامة الذكية)
  • يدخل (لإنشاء كعب الروتين)
  • F12 (انتقل إلى التعريف ليأخذك إلى الطريقة الجديدة)

تظهر العلامة الذكية فقط إذا اعتقد IDE أنه لا توجد طريقة مطابقة.إذا كنت تريد الإنشاء عندما لا تكون العلامة الذكية قيد التشغيل، فيمكنك الانتقال إلى تحرير->التحسس->إنشاء كعب روتين الطريقة.

مقتطفات.قوالب تعليمات برمجية صغيرة تجعل من السهل إنشاء أجزاء من التعليمات البرمجية الشائعة.بعضها بسيط (جرب "if[TAB][TAB]").بعضها معقد (سيؤدي "التبديل" إلى إنشاء حالات للتعداد).يمكنك أيضًا أن تكتب بنفسك.بالنسبة لحالتك، جرب "class" و"prop".

أنظر أيضا "كيفية تغيير "إنشاء كعب روتين الأسلوب" لرمي NotImplementedException في VS؟" للحصول على مقتطفات من المعلومات في سياق GMS.

أدوات تلقائية.تذكر أن الخصائص يمكن أن تكون أبسط بكثير:

public string Name { get; set; }

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

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

هذه ليست الحل الآلي بنسبة 100% الذي تبحث عنه، ولكن أعتقد أنه حل جيد.

أجد أنه عندما أحتاج إلى أداة لتوليد التعليمات البرمجية مثل هذه، فأنا على الأرجح أكتب تعليمات برمجية يمكن جعلها أكثر عمومية قليلاً، لذا أحتاج إلى كتابتها مرة واحدة فقط.في المثال الخاص بك، لا يبدو أن هذه الحروف والمحددات تضيف أي قيمة إلى الكود - في الواقع، فهي تؤكد فقط أن آلية getter/setter في C# تعمل.

سأمتنع عن كتابة (أو حتى استخدام) مثل هذه الأداة قبل أن أفهم ما هي دوافع كتابة هذا النوع من الاختبارات.

راجع للشغل، قد ترغب في إلقاء نظرة على نتصرف?

أستخدم Rhino Mocks لهذا الغرض، عندما أحتاج فقط إلى كعب بسيط.

http://www.ayende.com/wiki/Rhino+Mocks+-+Stubs.ashx

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