سؤال

كنت أتساءل عن كيفية اختبار الوحدة للفصول المجردة والفصول التي تعمل على توسيع الفئات المجردة.

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

هل يجب أن يكون لدي حالة اختبار مجردة يمكن استخدامها لاختبار أساليب الفئة المجردة وتوسيع هذه الفئة في حالة الاختبار الخاصة بي للكائنات التي تعمل على توسيع الفئة المجردة؟

لاحظ أن صفي التجريدي يحتوي على بعض الأساليب الملموسة.

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

المحلول

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

ويجب اختبار فئة مجردة التي تحتوي على بعض المنطق مثل جميع الفئات الأخرى لديك.

نصائح أخرى

هناك طريقتان يتم من خلالهما استخدام الفئات الأساسية المجردة.

  1. أنت تقوم بتخصيص كائنك المجرد، ولكن جميع العملاء سيستخدمون الفئة المشتقة من خلال واجهته الأساسية.

  2. أنت تستخدم فئة أساسية مجردة لاستبعاد التكرار داخل الكائنات في تصميمك، ويستخدم العملاء التطبيقات الملموسة من خلال واجهاتهم الخاصة.!


الحل لـ 1 - نمط الإستراتيجية

Option1

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

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

IMotor

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


الحل ل 2

إذا كان لديك الموقف الثاني، فإن فصلك التجريدي يعمل كفئة مساعدة.

AbstractHelper

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

Motor Helper

يؤدي هذا مرة أخرى إلى فئات محددة بسيطة وقابلة للاختبار بسهولة.


كقاعدة

تفضيل شبكة معقدة من الكائنات البسيطة على شبكة بسيطة من الكائنات المعقدة.

إن مفتاح الكود القابل للامتداد القابل للاختبار هو وحدات بناء صغيرة وأسلاك مستقلة.


محدث :كيفية التعامل مع خليط من كليهما؟

من الممكن أن يكون هناك فئة أساسية تؤدي كلا هذين الدورين ...أي:فهو يحتوي على واجهة عامة، ويحتوي على أساليب مساعدة محمية.إذا كان الأمر كذلك، فيمكنك تحليل الأساليب المساعدة إلى فئة واحدة (سيناريو 2) وتحويل شجرة الميراث إلى نمط إستراتيجية.

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


التحديث 2 :دروس مجردة كنقطة انطلاق (2014/06/12)

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

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

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

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

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

عند هذه النقطة، لن تحتاج فئات الإعدادات المكتوبة بقوة بعد الآن إلى أساليب "getter" التي تكشف تطبيق "الإعدادات" الأساسي.

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

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

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

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

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

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

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

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

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

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

إحدى الطرق هي كتابة حالة اختبار مجردة تتوافق مع فئتك المجردة، ثم كتابة حالات اختبار ملموسة تصنف حالة اختبار مجردة خاصة بك.افعل ذلك لكل فئة فرعية محددة من صفك التجريدي الأصلي (أي.يعكس التسلسل الهرمي لحالة الاختبار التسلسل الهرمي لفصلك).راجع اختبار الواجهة في كتاب المستلمين junit: http://safari.informit.com/9781932394238/ch02lev1sec6.

راجع أيضًا Testcase Superclass في أنماط xUnit: http://xunitpatterns.com/Testcase%20Superclass.html

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

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

وهذا هو النمط I عادة ما تتبع عند إعداد تسخير لاختبار فئة مجردة:

public abstract class MyBase{
  /*...*/
  public abstract void VoidMethod(object param1);
  public abstract object MethodWithReturn(object param1);
  /*,,,*/
}

والنسخة I استخدام تحت الاختبار:

public class MyBaseHarness : MyBase{
  /*...*/
  public Action<object> VoidMethodFunction;
  public override void VoidMethod(object param1){
    VoidMethodFunction(param1);
  }
  public Func<object, object> MethodWithReturnFunction;
  public override object MethodWithReturn(object param1){
    return MethodWihtReturnFunction(param1);
  }
  /*,,,*/
}

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

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

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

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

من منظور اختبار الوحدة، هناك أمران يجب مراعاتهما:

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

  2. وظائف الفئات المشتقة.إذا كان لديك منطق مخصص كتبته للفئات المشتقة، فيجب عليك اختبار تلك الفئات بشكل منفصل.

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

والأولى إذا فئة مجردة يتضمن بعض طريقة ملموسة أعتقد أن عليك أن تفعل هذا يعتبر هذا المثال

 public abstract class A 

 {

    public boolean method 1
    {
        // concrete method which we have to test.

    }


 }


 class B extends class A

 {

      @override
      public boolean method 1
      {
        // override same method as above.

      }


 } 


  class Test_A 

  {

    private static B b;  // reference object of the class B

    @Before
    public void init()

      {

      b = new B ();    

      }

     @Test
     public void Test_method 1

       {

       b.method 1; // use some assertion statements.

       }

   }

بعد إجابة @patrick-desjardins، قمت بتنفيذ الملخص وفئة التنفيذ معه @Test على النحو التالي:

فئة مجردة - ABC.java

import java.util.ArrayList;
import java.util.List;

public abstract class ABC {

    abstract String sayHello();

    public List<String> getList() {
        final List<String> defaultList = new ArrayList<>();
        defaultList.add("abstract class");
        return defaultList;
    }
}

مثل لا يمكن إنشاء مثيل للفئات المجردة، ولكن يمكن تصنيفها إلى فئات فرعية, فئة ملموسة DEF.java, ، على النحو التالي:

public class DEF extends ABC {

    @Override
    public String sayHello() {
        return "Hello!";
    }
}

@امتحان فئة لاختبار كل من الطريقة المجردة وغير المجردة:

import org.junit.Before;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.contains;
import java.util.Collection;
import java.util.List;
import static org.hamcrest.Matchers.equalTo;

import org.junit.Test;

public class DEFTest {

    private DEF def;

    @Before
    public void setup() {
        def = new DEF();
    }

    @Test
    public void add(){
        String result = def.sayHello();
        assertThat(result, is(equalTo("Hello!")));
    }

    @Test
    public void getList(){
        List<String> result = def.getList();
        assertThat((Collection<String>) result, is(not(empty())));
        assertThat(result, contains("abstract class"));
    }
}

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

لتجنب أي ارتباك في المستقبل، انتبه إلى أن فصل الاختبار الملموس هذا ليس محاكاة، ولكنه اختبار مزيف.

بعبارات صارمة، أ وهمية يتم تعريفه بالخصائص التالية:

  • يتم استخدام النموذج بدلاً من كل تبعية لفئة الموضوع الذي يتم اختباره.
  • النموذج الوهمي هو تطبيق زائف للواجهة (قد تتذكر أنه كقاعدة عامة، يجب الإعلان عن التبعيات كواجهات؛القابلية للاختبار هي أحد الأسباب الرئيسية لذلك)
  • يتم توفير سلوكيات أعضاء الواجهة الوهمية-سواء كانت أساليب أو خصائص-في وقت الاختبار (مرة أخرى ، عن طريق استخدام إطار السخرية).بهذه الطريقة، يمكنك تجنب اقتران التطبيق الذي يتم اختباره مع تنفيذ تبعياته (والتي يجب أن يكون لها جميعًا اختبارات منفصلة خاصة بها).
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top