كيف يمكنني اختبار وظيفة خاصة أو فئة لها أساليب أو حقول أو فئات داخلية خاصة؟

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

  •  09-06-2019
  •  | 
  •  

سؤال

كيف أقوم باختبار الوحدة (باستخدام xUnit) لفئة تحتوي على أساليب أو حقول أو فئات متداخلة داخلية خاصة؟أو وظيفة أصبحت خاصة من خلال امتلاكها الارتباط الداخلي (static في C/C++) أو في مكان خاص (مجهول) مساحة الاسم؟

يبدو أنه من السيئ تغيير معدّل الوصول لطريقة أو وظيفة فقط لتتمكن من إجراء الاختبار.

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

المحلول

تحديث:

بعد حوالي 10 سنوات، ربما تكون أفضل طريقة لاختبار طريقة خاصة، أو أي عضو لا يمكن الوصول إليه، هي عبر @Jailbreak من مشعب نطاق.

@Jailbreak Foo foo = new Foo();
// Direct, *type-safe* access to *all* foo's members
foo.privateMethod(x, y, z);
foo.privateField = value;

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

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

داخليًا، نستخدم مساعدين للحصول على/تعيين private و private static المتغيرات وكذلك الاستدعاء private و private static طُرق.ستتيح لك الأنماط التالية القيام بأي شيء يتعلق بالطرق والحقول الخاصة تقريبًا.بالطبع، لا يمكنك التغيير private static final المتغيرات من خلال الانعكاس

Method method = TargetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

و بالنسبة للحقول:

Field field = TargetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);

ملحوظات:
1. TargetClass.getDeclaredMethod(methodName, argClasses) يتيح لك النظر في private طُرق.نفس الشيء ينطبق على getDeclaredField.
2.ال setAccessible(true) مطلوب للعب مع أفراد.

نصائح أخرى

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

  1. الطريقة الخاصة هي رمز ميت
  2. توجد رائحة تصميم بالقرب من الفصل الذي تختبره
  3. يجب ألا تكون الطريقة التي تحاول اختبارها خاصة

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

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

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

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

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

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

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

من هذه المقالة: اختبار الطرق الخاصة باستخدام JUnit وSuiteRunner (بيل فينيرز)، لديك أساسًا 4 خيارات:

  • لا تختبر الأساليب الخاصة.
  • منح حق الوصول إلى حزمة الأساليب.
  • استخدم فئة اختبار متداخلة.
  • استخدم الانعكاس.

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

مثالان فقط على المكان الذي أرغب في اختبار طريقة خاصة فيه:

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

أفهم فكرة اختبار "العقد" فقط.لكنني لا أرى أنه يمكن للمرء أن يدعو فعليًا إلى عدم اختبار الكود - فقد يختلف عدد الأميال المقطوعة.

لذا فإن مقايضتي تتضمن تعقيد JUnits من خلال التفكير، بدلاً من المساس بأماني وSDK.

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

هناك طريقة أخرى استخدمتها وهي تغيير طريقة خاصة لحزم خاصة أو محمية ثم استكمالها بـ @VisibleForTesting شرح لمكتبة Google Guava.

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

على سبيل المثال، إذا كانت الطريقة المراد اختبارها موجودة src/main/java/mypackage/MyClass.java ثم يجب إجراء مكالمتك الاختبارية src/test/java/mypackage/MyClassTest.java.بهذه الطريقة، يمكنك الوصول إلى طريقة الاختبار في فصل الاختبار الخاص بك.

لاختبار التعليمات البرمجية القديمة باستخدام فئات كبيرة وغريبة، غالبًا ما يكون من المفيد جدًا أن تكون قادرًا على اختبار الطريقة الخاصة (أو العامة) التي أكتبها الآن.

انا استعمل ال junitx.util.PrivateAccessor-حزمة لجافا.الكثير من الخطوط المفيدة للوصول إلى الأساليب الخاصة والحقول الخاصة.

import junitx.util.PrivateAccessor;

PrivateAccessor.setField(myObjectReference, "myCrucialButHardToReachPrivateField", myNewValue);
PrivateAccessor.invoke(myObjectReference, "privateMethodName", java.lang.Class[] parameterTypes, java.lang.Object[] args);

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

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

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

مزايا:

  • يمكن اختبار لتفاصيل أدق

سلبيات:

  • يجب أن يقيم رمز الاختبار في نفس الملف مثل رمز المصدر ، والذي قد يكون من الصعب الحفاظ عليه
  • وبالمثل مع ملفات الإخراج .class، يجب أن تظل ضمن نفس الحزمة المعلن عنها في التعليمات البرمجية المصدر

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

فيما يلي مثال معقد لكيفية عمل ذلك:

// Import statements and package declarations

public class ClassToTest
{
    private int decrement(int toDecrement) {
        toDecrement--;
        return toDecrement;
    }

    // Constructor and the rest of the class

    public static class StaticInnerTest extends TestCase
    {
        public StaticInnerTest(){
            super();
        }

        public void testDecrement(){
            int number = 10;
            ClassToTest toTest= new ClassToTest();
            int decremented = toTest.decrement(number);
            assertEquals(9, decremented);
        }

        public static void main(String[] args) {
            junit.textui.TestRunner.run(StaticInnerTest.class);
        }
    }
}

سيتم تجميع الطبقة الداخلية ل ClassToTest$StaticInnerTest.

أنظر أيضا: نصيحة جافا 106:فصول داخلية ثابتة من أجل المتعة والربح

وكما قال الآخرون...لا تختبر الطرق الخاصة مباشرةً.وفيما يلي بعض الأفكار:

  1. اجعل جميع الأساليب صغيرة ومركزة (سهلة الاختبار، ومن السهل العثور على الأخطاء)
  2. استخدم أدوات تغطية التعليمات البرمجية.انا يعجبني كوبرتورا (يوم سعيد، يبدو أن الإصدار الجديد قد صدر!)

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

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

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

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

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

في ال إطار الربيع يمكنك اختبار الطرق الخاصة باستخدام هذه الطريقة:

ReflectionTestUtils.invokeMethod()

على سبيل المثال:

ReflectionTestUtils.invokeMethod(TestClazz, "createTest", "input data");

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

ReflectionTestUtils.setField(theClass, "theUnsettableField", theMockObject);

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

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

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

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

لذلك لا تختبر الأساليب الخاصة.

الجواب من صفحة الأسئلة الشائعة الخاصة بـ JUnit.org:

ولكن إذا كان لا بد من ذلك...

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

إذا كنت تستخدم JDK 1.6 أو أعلى وقمت بتعليق الاختبارات الخاصة بك باستخدام اختبار test ، فيمكنك الاستخدام Dp4j لحقن الانعكاس في طرق الاختبار الخاصة بك.للحصول على تفاصيل حول كيفية استخدامه ، انظر هذا البرنامج النصي للاختبار.

ملاحظة.أنا المساهم الرئيسي في Dp4j, ، بسأل أنا إذا كنت بحاجة إلى مساعدة.:)

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

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

إذا كنت تستخدم JUnit، قم بإلقاء نظرة على junit-addons.لديه القدرة على تجاهل نموذج أمان Java والوصول إلى الأساليب والسمات الخاصة.

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

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

إذا كان كل ما سبق لا يناسب متطلباتك، استخدم طريقة الانعكاس للوصول إلى الطريقة الخاصة.

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

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

public class ClassToTest {

    private final String first = "first";
    private final List<String> second = new ArrayList<>();
    ...
}

كنت قد استخدمت هذا:

public class ClassToTest {

    private final String first;
    private final List<String> second;

    public ClassToTest() {
        this("first", new ArrayList<>());
    }

    public ClassToTest(final String first, final List<String> second) {
        this.first = first;
        this.second = second;
    }
    ...
}

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

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

public ClassToTest() {
    this(...);
}

public ClassToTest(final Callable<T> privateMethodLogic) {
    this.privateMethodLogic = privateMethodLogic;
}

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

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

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

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

إذا قمت بذلك، فمن الجيد استخدام أداة تغطية التعليمات البرمجية (مثل Emma) لمعرفة ما إذا كان يتم بالفعل تنفيذ أساليبك الخاصة من خلال اختباراتك.

هذه هي وظيفتي العامة لاختبار الحقول الخاصة:

protected <F> F getPrivateField(String fieldName, Object obj)
    throws NoSuchFieldException, IllegalAccessException {
    Field field =
        obj.getClass().getDeclaredField(fieldName);

    field.setAccessible(true);
    return (F)field.get(obj);
}

يرجى الاطلاع أدناه للحصول على مثال؛

يجب إضافة بيان الاستيراد التالي:

import org.powermock.reflect.Whitebox;

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

Whitebox.invokeMethod(obj, "privateMethod", "param1");

اليوم، قمت بدفع مكتبة Java للمساعدة في اختبار الأساليب والمجالات الخاصة.لقد تم تصميمه مع وضع Android في الاعتبار، ولكن يمكن استخدامه حقًا لأي مشروع Java.

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

@UiThreadTest
public void testCompute() {

    // Given
    boundBoxOfMainActivity = new BoundBoxOfMainActivity(getActivity());

    // When
    boundBoxOfMainActivity.boundBox_getButtonMain().performClick();

    // Then
    assertEquals("42", boundBoxOfMainActivity.boundBox_getTextViewMain().getText());
}

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

إنه مثالي لاختبار بعض التعليمات البرمجية القديمة.استخدمه بعناية.;)

https://github.com/stephanenicolas/boundbox

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

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

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

لقد واجهت هذه المشكلة مؤخرًا وكتبت أداة صغيرة تسمى معول, ، الذي يتجنب مشاكل الاستخدام الصريح لواجهة برمجة تطبيقات انعكاس Java، مثالان:

طرق الاتصال، على سبيل المثال. private void method(String s) - عن طريق انعكاس جافا

Method method = targetClass.getDeclaredMethod("method", String.class);
method.setAccessible(true);
return method.invoke(targetObject, "mystring");

طرق الاتصال، على سبيل المثال. private void method(String s) - بواسطة بيكلوك

interface Accessible {
  void method(String s);
}

...
Accessible a = ObjectAccess.unlock(targetObject).features(Accessible.class);
a.method("mystring");

حقول الإعداد، على سبيل المثال. private BigInteger amount; - عن طريق انعكاس جافا

Field field = targetClass.getDeclaredField("amount");
field.setAccessible(true);
field.set(object, BigInteger.valueOf(42));

حقول الإعداد، على سبيل المثال. private BigInteger amount; - بواسطة بيكلوك

interface Accessible {
  void setAmount(BigInteger amount);
}

...
Accessible a = ObjectAccess.unlock(targetObject).features(Accessible.class);
a.setAmount(BigInteger.valueOf(42));

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

لا يمكنك استخدام الانعكاس للحصول على أساليب خاصة من خارج فئة المالك، ويؤثر المعدل الخاص على الانعكاس أيضًا

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

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