سؤال

وأنا بحاجة لمحاكاة سيناريو اختبار الذي أسميه طريقة getBytes() كائن سلسلة وأحصل على UnsupportedEncodingException.

ولقد حاولت أن تحقيق ذلك باستخدام التعليمات البرمجية التالية:

String nonEncodedString = mock(String.class);
when(nonEncodedString.getBytes(anyString())).thenThrow(new UnsupportedEncodingException("Parsing error."));

والمشكلة هي أنني عندما تشغيل حالتي اختبار أحصل على MockitoException تقول لا أستطيع أن يسخر فئة java.lang.String.

هل هناك طريقة للسخرية كائن سلسلة باستخدام mockito، أو بدلا من ذلك، وسيلة لجعل الكائن سلسلة بلدي بطرح UnsupportedEncodingException عندما استدعاء الأسلوب getBytes؟


وفيما يلي مزيد من التفاصيل لتوضيح المشكلة:

وهذه هي الفئة التي أريد أن الاختبار:

public final class A {
    public static String f(String str){
        try {
            return new String(str.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            // This is the catch block that I want to exercise.
            ...
        }
    }
}

وهذا هو صفي الاختبار (أنا باستخدام أداة JUnit 4 و mockito):

public class TestA {

    @Test(expected=UnsupportedEncodingException.class)
    public void test(){
        String aString = mock(String.class);
        when(nonEncodedString.getBytes(anyString())).thenThrow(new UnsupportedEncodingException("Parsing error."));
        A.f(aString);
    }
}
هل كانت مفيدة؟

المحلول

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

نصائح أخرى

وماذا عن مجرد خلق String مع اسم ترميز سيئة؟ انظر

public String(byte bytes[], int offset, int length, String charsetName)

والاستهزاء String يكاد يكون من المؤكد فكرة سيئة.

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

public final class A{
    public static String f(String str){
        return new String(str.getBytes(Charset.forName("UTF-8")));
    }
}

وهذه الطريقة التي لم يتم اصطياد استثناء لن يحدث أبدا فقط لأن المترجم يخبرك.

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

وأيضا، تسبب نفس المشكلة لالمتصل A.f() لA نهائي وf() ثابت.

وربما تكون هذه المقالة مفيدة في إقناع زملاء العمل الخاص بك لتكون أقل عقائدية حوالي 100٪ تغطية رمز: <لأ href = "http://jasonrudolph.com/blog/testing-anti-patterns-how-to-fail-with -100 اختبار التغطية / "يختلط =" noreferrer "> كيف فشل مع 100٪ تغطية اختبار .

ومن وثائقها، JDave لا يمكن إزالة معدلات "النهائية" من الطبقات تحميلها من قبل classloader التمهيد. وهذا يشمل جميع فئات JRE (من java.lang، java.util، الخ.).

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

ومع JMockit، الاختبار يمكن أن تكون مكتوبة على النحو التالي:

import java.io.*;
import org.junit.*;
import mockit.*;

public final class ATest
{
   @Test(expected = UnsupportedOperationException.class)
   public void test() throws Exception
   {
      new Expectations()
      {
         @Mocked("getBytes")
         String aString;

         {
            aString.getBytes(anyString);
            result = new UnsupportedEncodingException("Parsing error.");
         }
      };

      A.f("test");
   }
}

وعلى افتراض أن كاملة "A" الطبقة هي:

import java.io.*;

public final class A
{
   public static String f(String str)
   {
      try {
         return new String(str.getBytes("UTF-8"));
      }
      catch (UnsupportedEncodingException e) {
         throw new UnsupportedOperationException(e);
      }
   }
}

وأنا فعلا تنفيذ هذا الاختبار في الجهاز الخاص بي. (لاحظ أنا ملفوفة باستثناء فحص الأصلي في استثناء وقت التشغيل.)

وكنت ساخرا جزئي من خلال @Mocked("getBytes") لمنع JMockit من يسخر كل شيء في فئة java.lang.String (فقط تخيل ما يمكن أن يسبب).

والآن، وهذا الاختبار هو في الحقيقة لا داعي لها، لأن "UTF-8" هو محارف القياسية المطلوبة لتكون معتمدة في كل JREs. ولذلك، في بيئة الإنتاج لن يتم تنفيذها كتلة الصيد.

وو"الحاجة" أو الرغبة في تغطية كتلة الصيد لا تزال سارية المفعول، وإن كان. لذا، وكيفية التخلص من الاختبار دون خفض نسبة التغطية؟ هنا هي فكرتي: إدراج سطر مع assert false; كما البيان الأول داخل كتلة التقاط ويكون أداة تغطية رمز تتجاهل كتلة التقاط كله عند الإبلاغ عن التدابير التغطية. هذا هو واحد من بلادي "البنود TODO" لتغطية JMockit. 8 ^)

وMockito لا يمكن أن يسخر الطبقات النهائية. JMock، جنبا إلى جنب مع مكتبة من JDave يمكن. هنا التعليمات .

وJMock لا تفعل أي شيء خاص لفئات أخرى النهائية من الاعتماد على مكتبة JDave إلى unfinalize كل شيء في JVM، لذلك يمكن أن تجربة استخدام unfinalizer JDave ومعرفة ما إذا كان سوف Mockito ثم يسخرون منه.

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

وسوف يتم اختبار التعليمات البرمجية التي لا يمكن أبدا أن يتم تنفيذها. مطلوب دعم UTF-8 ليكون في كل جافا VM، انظر> وأ href = "http://java.sun.com/javase/6/docs/api/java/nio/charset/Charset.html" يختلط = " noreferrer نوفولو "> http://java.sun.com/javase/6/docs/api/java/nio/charset/Charset.html

<اقتباس فقرة>   

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

ما هو أنه نظرا الهدف تغطية؟ قد يقول البعض أن اطلاق النار للتغطية 100٪ ليست دائما جيدة فكرة .

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

@Test(expected=IndexOutOfBoundsException.class) public void outOfBounds() {
   new ArrayList<Object>().get(1);
}

هل حاولت تمرير charsetName غير صالحة للgetBytes (سلسلة)؟

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

وربما A.f (سلسلة) يجب أن يكون A.f (CharSequence) بدلا من ذلك. يمكنك يسخر من CharSequence.

إذا يمكنك استخدام JMockit، والنظر في روجيريو الإجابة.

إذا وفقط إذا كان هدفك هو الحصول على مدونة التغطية ولكن ليس محاكاة الواقع ما المفقود UTF-8 ستبدو في وقت التشغيل يمكنك القيام بما يلي (وأنك لا تستطيع أو لا تريد استخدام JMockit):

public static String f(String str){
    return f(str, "UTF-8");
}

// package private for example
static String f(String str, String charsetName){
    try {
        return new String(str.getBytes(charsetName));
    } catch (UnsupportedEncodingException e) {
        throw new IllegalArgumentException("Unsupported encoding: " + charsetName, e);
    }
}

public class TestA {

    @Test(expected=IllegalArgumentException.class)
    public void testInvalid(){
        A.f(str, "This is not the encoding you are looking for!");
    }

    @Test
    public void testNormal(){
        // TODO do the normal tests with the method taking only 1 parameter
    }
}

ويمكنك تغيير طريقة لاتخاذ CharSequence اجهة:

public final class A {
    public static String f(CharSequence str){
        try {
            return new String(str.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            // This is the catch block that I want to exercise.
            ...
        }
    }
}

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

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

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

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