java شرح - كيف تؤكد أنه تم طرح استثناء معين في اختبارات JUnit 4؟




download tutorial (25)

Take for example, you want to write Junit for below mentioned code fragment

public int divideByZeroDemo(int a,int b){

    return a/b;
}

public void exceptionWithMessage(String [] arr){

    throw new ArrayIndexOutOfBoundsException("Array is out of bound");
}

The above code is to test for some unknown exception that may occur and the below one is to assert some exception with custom message.

 @Rule
public ExpectedException exception=ExpectedException.none();

private Demo demo;
@Before
public void setup(){

    demo=new Demo();
}
@Test(expected=ArithmeticException.class)
public void testIfItThrowsAnyException() {

    demo.divideByZeroDemo(5, 0);

}

@Test
public void testExceptionWithMessage(){


    exception.expectMessage("Array is out of bound");
    exception.expect(ArrayIndexOutOfBoundsException.class);
    demo.exceptionWithMessage(new String[]{"This","is","a","demo"});
}

كيف يمكنني استخدام JUnit4 اصطلاعا لاختبار أن بعض التعليمات البرمجية تطرح استثناء؟

بينما يمكنني بالتأكيد فعل شيء كالتالي:

@Test
public void testFooThrowsIndexOutOfBoundsException() {
  boolean thrown = false;

  try {
    foo.doStuff();
  } catch (IndexOutOfBoundsException e) {
    thrown = true;
  }

  assertTrue(thrown);
}

أذكر أن هناك تعليقًا توضيحيًا أو Assert.xyz أو شيئًا أقل بكثير من kludgy وأكثر بكثير من روح JUnit لهذه الأنواع من المواقف.


حل جافا 8

إذا كنت ترغب في حل ما يلي:

  • يستخدم lambdas جافا 8
  • لا يعتمد على أي سحر JUnit
  • يسمح لك بالتحقق من وجود استثناءات متعددة داخل طريقة اختبار واحدة
  • التحقق من وجود استثناء يتم طرحه بواسطة مجموعة محددة من الخطوط داخل طريقة الاختبار الخاصة بك بدلاً من أي سطر غير معروف في طريقة الاختبار بالكامل
  • يعطي كائن الاستثناء الفعلي الذي تم طرحه حتى يمكنك فحصه بشكل أكبر

وهنا وظيفة الأداة التي كتبت:

public final <T extends Throwable> T expectException( Class<T> exceptionClass, Runnable runnable )
{
    try
    {
        runnable.run();
    }
    catch( Throwable throwable )
    {
        if( throwable instanceof AssertionError && throwable.getCause() != null )
            throwable = throwable.getCause(); //allows "assert x != null : new IllegalArgumentException();"
        assert exceptionClass.isInstance( throwable ) : throwable; //exception of the wrong kind was thrown.
        assert throwable.getClass() == exceptionClass : throwable; //exception thrown was a subclass, but not the exact class, expected.
        @SuppressWarnings( "unchecked" )
        T result = (T)throwable;
        return result;
    }
    assert false; //expected exception was not thrown.
    return null; //to keep the compiler happy.
}

( مأخوذة من مدونتي )

استخدمه على النحو التالي:

@Test
public void testThrows()
{
    RuntimeException e = expectException( RuntimeException.class, () -> 
        {
            throw new RuntimeException( "fail!" );
        } );
    assert e.getMessage().equals( "fail!" );
}


في junit ، توجد ثلاث طرق لاختبار الاستثناء.

  • استخدم السمة "المتوقعة" الاختيارية للتأخير التجريبي

    @Test(expected = IndexOutOfBoundsException.class)
    public void testFooThrowsIndexOutOfBoundsException() {
        foo.doStuff();
    }
    
  • استخدم قاعدة ExpectedException

    public class XxxTest {
        @Rule
        public ExpectedException thrown = ExpectedException.none();
    
        @Test
        public void testFooThrowsIndexOutOfBoundsException() {
            thrown.expect(IndexOutOfBoundsException.class)
            //you can test the exception message like
            thrown.expectMessage("expected messages");
            foo.doStuff();
        }
    }
    
  • وأخيرًا ، يمكنك أيضًا استخدام طريقة المحاولة / التجميع الكلاسيكية التي يتم استخدامها على نطاق واسع في إطار برنامج junit 3

    @Test
    public void testFooThrowsIndexOutOfBoundsException() {
        try {
            foo.doStuff();
            fail("expected exception was not occured.");
        } catch(IndexOutOfBoundsException e) {
            //if execution reaches here, 
            //it indicates this exception was occured.
            //so we need not handle it.
        }
    }
    
  • وبالتالي

    • الطريقة الأولى المستخدمة عندما تريد فقط اختبار نوع الاستثناء
    • الطريقة الثانية والثالثة المستخدمة عندما تريد رسالة استثناء اختبار إضافية
    • إذا كنت تستخدم Junit 3 ، فسيفضل الثالث.
  • لمزيد من المعلومات ، يمكنك قراءة github.com/junit-team/junit/wiki/Exception-testing للحصول على التفاصيل.


JUnit 4 لديه دعم لهذا:

@Test(expected = IndexOutOfBoundsException.class)
public void testIndexOutOfBoundsException() {
    ArrayList emptyList = new ArrayList();
    Object o = emptyList.get(0);
}

المرجع: https://junit.org/junit4/faq.html#atests_7


تحرير الآن بعد أن أصدرت JUnit5 ، فإن أفضل خيار هو استخدام Assertions.assertThrows() (انظر جوابي الآخر ).

إذا لم تقم بالترحيل إلى JUnit 5 ، ولكن يمكنك استخدام JUnit 4.7 ، يمكنك استخدام قاعدة ExpectedException :

public class FooTest {
  @Rule
  public final ExpectedException exception = ExpectedException.none();

  @Test
  public void doStuffThrowsIndexOutOfBoundsException() {
    Foo foo = new Foo();

    exception.expect(IndexOutOfBoundsException.class);
    foo.doStuff();
  }
}

هذا أفضل بكثير من @Test(expected=IndexOutOfBoundsException.class) لأن الاختبار ستفشل إذا تم طرح foo.doStuff() قبل foo.doStuff()

انظر هذه المادة لمزيد من التفاصيل


ليرة تركية، والدكتور

  • قبل JDK8: سأوصي try الجيدة القديمة - كتلة catch .

  • post-JDK8: استخدم AssertJ أو lambdas مخصصة لتأكيد السلوك الاستثنائي .

القصة الطويلة

من الممكن أن تكتب نفسك بنفسك - قم try الحظر أو استخدام أدوات JUnit ( @Test(expected = ...) أو @Rule ExpectedException القاعدة @Rule ExpectedException JUnit).

ولكن هذه الطريقة ليست غاية في الأناقة ولا تمزج سهولة القراءة مع الأدوات الأخرى.

  1. كتلة try يجب أن تكتب الكتلة حول السلوك المختبر، وتكتب التوكيد في كتلة المصيد، التي قد تكون جيدة لكن الكثير يجد taht هذا الأسلوب يقطع تدفق القراءة للاختبار. كما تحتاج إلى كتابة Assert.fail في نهاية كتلة try وإلا قد يغيب الاختبار جانب واحد من التأكيدات. PMD ، findbugs أو Sonar سوف يكتشف مثل هذه القضايا.

  2. @Test(expected = ...) مثيرة للاهتمام حيث يمكنك كتابة @Test(expected = ...) برمجية أقل ، ومن ثم كتابة هذا الاختبار أقل عرضة للأخطاء البرمجية. لكن النهج المذكور يفتقر إلى بعض المناطق.

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

      @Test(expected = WantedException.class)
      public void call2_should_throw_a_WantedException__not_call1() {
          // init tested
          tested.call1(); // may throw a WantedException
      
          // call to be actually tested
          tested.call2(); // the call that is supposed to raise an exception
      }
      
  3. إن قاعدة ExpectedException هي أيضًا محاولة لإصلاح التحذيرات السابقة ، ولكنها تبدو محرجة بعض الشيء لاستخدامها لأنها تستخدم أسلوبًا متوقعًا ، يعرف مستخدمو EasyMock هذا النمط جيدًا. قد يكون مناسبًا للبعض ، لكن إذا اتبعت مبادئ تطوير السلوكيات (BDD) أو Arrange Act Assert (AAA) فإن قاعدة ExpectedException لن تلائم نمط الكتابة تلك. إلى جانب ذلك ، قد يعاني من نفس المشكلة مثل طريقة @Test ، حسب المكان الذي تضع فيه التوقعات.

    @Rule ExpectedException thrown = ExpectedException.none()
    
    @Test
    public void call2_should_throw_a_WantedException__not_call1() {
        // expectations
        thrown.expect(WantedException.class);
        thrown.expectMessage("boom");
    
        // init tested
        tested.call1(); // may throw a WantedException
    
        // call to be actually tested
        tested.call2(); // the call that is supposed to raise an exception
    }
    

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

    انظر أيضا هذه المسألة comment على JUnit للمؤلف ExpectedException .

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

  1. هناك مشروع تعرفت عليه بعد إنشاء هذه الإجابة التي تبدو واعدة ، ولكنها catch-exception .

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

    مثال سريع مأخوذ من الصفحة الرئيسية:

    // given: an empty list
    List myList = new ArrayList();
    
    // when: we try to get the first element of the list
    when(myList).get(1);
    
    // then: we expect an IndexOutOfBoundsException
    then(caughtException())
            .isInstanceOf(IndexOutOfBoundsException.class)
            .hasMessage("Index: 1, Size: 0") 
            .hasNoCause();
    

    كما يمكنك مشاهدة التعليمات البرمجية مباشرة ، يمكنك التقاط الاستثناء على سطر معين ، then API هو الاسم المستعار الذي سيستخدم AssertJ APIs (مثل استخدام assertThat(ex).hasNoCause()... ). في مرحلة ما اعتمد المشروع على FEST-Assert على سلف AssertJ . تحرير: يبدو أن المشروع هو تختمر دعم جافا 8 Lambdas.

    حاليا هذه المكتبة لديها اثنين من أوجه القصور:

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

    • يتطلب تبعية اختبار أخرى.

    لن يتم تطبيق هذه المشكلات بمجرد دعم المكتبة lambdas ، ولكن سيتم تكرار الوظيفة بواسطة مجموعة أدوات AssertJ.

    مع الأخذ في الاعتبار إذا كنت لا ترغب في استخدام أداة الاستثناء ، سأوصي بالطريقة الجيدة القديمة لكتلة try - catch ، على الأقل حتى JDK7. وبالنسبة لمستخدمي JDK 8 ، قد تفضل استخدام AssertJ كما يقدم ، أكثر من مجرد التأكيد على الاستثناءات.

  2. مع JDK8 ، تدخل lambdas إلى مسرح الاختبار ، وقد أثبتت أنها وسيلة مثيرة للاهتمام لتأكيد السلوك الاستثنائي. تم تحديث AssertJ لتوفير واجهة برمجة تطبيقات لطيفة بطلاقة لتأكيد السلوك الاستثنائي.

    واختبار عينة مع AssertJ :

    @Test
    public void test_exception_approach_1() {
        ...
        assertThatExceptionOfType(IOException.class)
                .isThrownBy(() -> someBadIOOperation())
                .withMessage("boom!"); 
    }
    
    @Test
    public void test_exception_approach_2() {
        ...
        assertThatThrownBy(() -> someBadIOOperation())
                .isInstanceOf(Exception.class)
                .hasMessageContaining("boom");
    }
    
    @Test
    public void test_exception_approach_3() {
        ...
        // when
        Throwable thrown = catchThrowable(() -> someBadIOOperation());
    
        // then
        assertThat(thrown).isInstanceOf(Exception.class)
                          .hasMessageContaining("boom");
    }
    
  3. مع إعادة كتابة شبه كاملة من JUnit 5 ، تم improved التأكيدات قليلاً ، قد تثبت أنها مثيرة للاهتمام كوسيلة من خارج منطقة الجزاء لتأكيد الاستثناء بشكل صحيح. ولكن في الحقيقة ، لا تزال واجهة برمجة تطبيقات التأكيد ضعيفة بعض الشيء ، ولا يوجد شيء خارج assertThrows .

    @Test
    @DisplayName("throws EmptyStackException when peeked")
    void throwsExceptionWhenPeeked() {
        Throwable t = assertThrows(EmptyStackException.class, () -> stack.peek());
    
        Assertions.assertEquals("...", t.getMessage());
    }
    

    كما لاحظت assertEquals لا يزال العائد void ، وعلى هذا النحو لا تسمح تسلسل التأكيدات مثل AssertJ.

    أيضًا إذا كنت تتذكر اسمًا Matcher مع Matcher أو Assert ، Assert مستعدًا لمواجهة الصدام نفسه مع Assertions .

أود أن أخلص إلى أن اليوم (2017-03-03) سهولة الاستخدام AssertJ ، API القابلة للاكتشاف ، وتيرة التطور السريع وكاعتماد اختبار الواقع هو الحل الأفضل مع JDK8 بغض النظر عن إطار الاختبار (JUnit أو لا) ، يجب أن تعتمد JDKs بدلاً من ذلك على كتل try حتى لو شعرت بالكلام.

لقد تم نسخ هذا الجواب من سؤال آخر ليس له نفس الرؤية ، فأنا نفس المؤلف.


Just make a Matcher that can be turned off and on, like this:

public class ExceptionMatcher extends BaseMatcher<Throwable> {
    private boolean active = true;
    private Class<? extends Throwable> throwable;

    public ExceptionMatcher(Class<? extends Throwable> throwable) {
        this.throwable = throwable;
    }

    public void on() {
        this.active = true;
    }

    public void off() {
        this.active = false;
    }

    @Override
    public boolean matches(Object object) {
        return active && throwable.isAssignableFrom(object.getClass());
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("not the covered exception type");
    }
}

To use it:

add public ExpectedException exception = ExpectedException.none(); , then:

ExceptionMatcher exMatch = new ExceptionMatcher(MyException.class);
exception.expect(exMatch);
someObject.somethingThatThrowsMyException();
exMatch.off();

JUnit 5 الحل

@Test
void testFooThrowsIndexOutOfBoundsException() {    
  Throwable exception = expectThrows( IndexOutOfBoundsException.class, foo::doStuff );

  assertEquals( "some message", exception.getMessage() );
}

مزيد من المعلومات عن JUnit 5 على improved


I wanted to comment with my solution to this problem, which avoided needing any of the exception related JUnit code.

I used assertTrue(boolean) combined with try/catch to look for my expected exception to be thrown. إليك مثال على ذلك:

public void testConstructor() {
    boolean expectedExceptionThrown;
    try {
        // Call constructor with bad arguments
        double a = 1;
        double b = 2;
        double c = a + b; // In my example, this is an invalid option for c
        new Triangle(a, b, c);
        expectedExceptionThrown = false; // because it successfully constructed the object
    }
    catch(IllegalArgumentException e) {
        expectedExceptionThrown = true; // because I'm in this catch block
    }
    catch(Exception e) {
        expectedExceptionThrown = false; // because it threw an exception but not the one expected
    }
    assertTrue(expectedExceptionThrown);
}

There are two ways of writing test case

  1. Annotate the test with the exception which is thrown by the method. Something like this @Test(expected = IndexOutOfBoundsException.class)
  2. You can simply catch the exception in the test class using the try catch block and assert on the message that is thrown from the method in test class.

    try{
    }
    catch(exception to be thrown from method e)
    {
         assertEquals("message", e.getmessage());
    }
    

I hope this answers your query Happy learning...


لحل نفس المشكلة ، أعددت مشروعًا صغيرًا: http://code.google.com/p/catch-exception/

باستخدام هذا المساعد الصغير ستكتب

verifyException(foo, IndexOutOfBoundsException.class).doStuff();

هذا أقل من verbose من قاعدة ExpectedException من JUnit 4.7. بالمقارنة مع الحل المقدم من قبل skaffman ، يمكنك تحديد سطر الشفرة الذي تتوقع فيه الاستثناء. آمل أن يساعد هذا.


كما تمت الإجابة من قبل ، هناك العديد من الطرق للتعامل مع الاستثناءات في JUnit. ولكن مع Java 8 ، هناك واحد آخر: باستخدام تعبيرات Lambda. مع تعبيرات Lambda يمكننا تحقيق صيغة كالتالي:

@Test
public void verifiesTypeAndMessage() {
    assertThrown(new DummyService()::someMethod)
            .isInstanceOf(RuntimeException.class)
            .hasMessage("Runtime exception occurred")
            .hasMessageStartingWith("Runtime")
            .hasMessageEndingWith("occurred")
            .hasMessageContaining("exception")
            .hasNoCause();
}

assertThrown يقبل واجهة وظيفية ، يمكن إنشاء مثيلاتها باستخدام تعبيرات lambda أو مراجع أسلوب أو مراجع منشئ. يؤكد assertThrown قبول تلك الواجهة وتكون جاهزة لمعالجة استثناء.

هذه تقنية بسيطة نسبياً لكنها قوية.

إلقاء نظرة على هذا بلوق وظيفة تصف هذه التقنية: http://blog.codeleak.pl/2014/07/junit-testing-exception-with-java-8-and-lambda-expressions.html

يمكن العثور على رمز المصدر هنا: https://github.com/kolorobot/unit-testing-demo/tree/master/src/test/java/com/github/kolorobot/exceptions/java8

الإفصاح: أنا مؤلف المدونة والمشروع.



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

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

try {
    methodThatShouldThrow();
    fail( "My method didn't throw when I expected it to" );
} catch (MyException expectedException) {
}

تطبيق الحكم.


تحديث: JUnit5 لديه تحسن لاختبار الاستثناءات: assertThrows .

المثال التالي من: دليل المستخدم Junit 5

 @Test
void exceptionTesting() {
    Throwable exception = assertThrows(IllegalArgumentException.class, () -> 
    {
        throw new IllegalArgumentException("a message");
    });
    assertEquals("a message", exception.getMessage());
}

الإجابة الأصلية باستخدام JUnit 4.

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

قم بتعيين المعلمة expected @Test(expected = FileNotFoundException.class) .

@Test(expected = FileNotFoundException.class) 
public void testReadFile() { 
    myClass.readFile("test.txt");
}

باستخدام try catch

public void testReadFile() { 
    try {
        myClass.readFile("test.txt");
        fail("Expected a FileNotFoundException to be thrown");
    } catch (FileNotFoundException e) {
        assertThat(e.getMessage(), is("The file test.txt does not exist!"));
    }

}

اختبار مع قاعدة ExpectedException .

@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void testReadFile() throws FileNotFoundException {

    thrown.expect(FileNotFoundException.class);
    thrown.expectMessage(startsWith("The file test.txt"));
    myClass.readFile("test.txt");
}

يمكنك قراءة المزيد عن اختبار الاستثناءات في JUnit4 wiki لاختبار الاستثناء و bad.robot - توقع الاستثناءات JUnit Rule .


والآن بعد إصدار JUnit 5 ، فإن أفضل خيار هو استخدام Assertions.assertThrows() (راجع دليل المستخدم Junit 5 ).

في ما يلي مثال يتحقق من طرح استثناء ، ويستخدم Truth لتأكيد التأكيدات على رسالة الاستثناء:

public class FooTest {
  @Test
  public void doStuffThrowsIndexOutOfBoundsException() {
    Foo foo = new Foo();

    IndexOutOfBoundsException e = assertThrows(
        IndexOutOfBoundsException.class, foo::doStuff);

    assertThat(e).hasMessageThat().contains("woops!");
  }
}

المزايا على النهج في الإجابات الأخرى هي:

  1. بنيت في JUnit
  2. يمكنك الحصول على رسالة استثناء مفيدة إذا كان الرمز في lambda لا يلقي استثناءً ، و stacktrace إذا كان يلقي استثناء مختلف
  3. مختصرا
  4. يسمح لاختباراتك باتباع Arrange-Act-Assert
  5. يمكنك الإشارة بدقة إلى الرمز الذي تتوقع أن يلقي الاستثناء
  6. لا تحتاج إلى سرد الاستثناء المتوقع في جملة throws
  7. يمكنك استخدام إطار التوكيد الذي تختاره لتقديم تأكيدات حول الاستثناء الذي تم اكتشافه

سيتم إضافة طريقة مشابهة إلى org.junit Assert في JUnit 4.13.


We can use an assertion fail after the method that must return an exception:

try{
   methodThatThrowMyException();
   Assert.fail("MyException is not thrown !");
} catch (final Exception exception) {
   // Verify if the thrown exception is instance of MyException, otherwise throws an assert failure
   assertTrue(exception instanceof MyException, "An exception other than MyException is thrown !");
   // In case of verifying the error message
   MyException myException = (MyException) exception;
   assertEquals("EXPECTED ERROR MESSAGE", myException.getMessage());
}

لقد جربت العديد من الأساليب هنا ، لكنها كانت معقدة أو لم تستوفِ متطلباتي تمامًا. في الواقع ، يمكن للمرء أن يكتب طريقة المساعد بكل بساطة:

public class ExceptionAssertions {
    public static void assertException(BlastContainer blastContainer ) {
        boolean caughtException = false;
        try {
            blastContainer.test();
        } catch( Exception e ) {
            caughtException = true;
        }
        if( !caughtException ) {
            throw new AssertionFailedError("exception expected to be thrown, but was not");
        }
    }
    public static interface BlastContainer {
        public void test() throws Exception;
    }
}

استخدمه على النحو التالي:

assertException(new BlastContainer() {
    @Override
    public void test() throws Exception {
        doSomethingThatShouldExceptHere();
    }
});

صفر الاعتماديات: لا حاجة إلى موكيتو ، لا حاجة إلى powermock ؛ ويعمل بشكل جيد مع الفصول النهائية.


The most flexible and elegant answer for Junit 4 I found in the Mkyoung blog . It have the flexibility of the try/catch using the @Rule. I like this approach because I need to read specific attributes of a customized exception.

package com.mkyong;

import com.mkyong.examples.CustomerService;
import com.mkyong.examples.exception.NameNotFoundException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.hasProperty;

public class Exception3Test {

    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @Test
    public void testNameNotFoundException() throws NameNotFoundException {

        //test specific type of exception
        thrown.expect(NameNotFoundException.class);

        //test message
        thrown.expectMessage(is("Name is empty!"));

        //test detail
        thrown.expect(hasProperty("errCode"));  //make sure getters n setters are defined.
        thrown.expect(hasProperty("errCode", is(666)));

        CustomerService cust = new CustomerService();
        cust.findByName("");

    }

}

With Java 8 you can create a method taking a code to check and expected exception as parameters:

private void expectException(Runnable r, Class<?> clazz) { 
    try {
      r.run();
      fail("Expected: " + clazz.getSimpleName() + " but not thrown");
    } catch (Exception e) {
      if (!clazz.isInstance(e)) fail("Expected: " + clazz.getSimpleName() + " but " + e.getClass().getSimpleName() + " found", e);
    }
  }

and then inside your test:

expectException(() -> list.sublist(0, 2).get(2), IndexOutOfBoundsException.class);

Benefits:

  • not relying on any library
  • localised check - more precise and allows to have multiple assertions like this within one test if needed
  • easy to use

في حالتي دائما الحصول على RuntimeException من ديسيبل ، ولكن الرسائل تختلف. والاستثناء تحتاج إلى التعامل معها على التوالي. إليك كيف اختبرت ذلك:

@Test
public void testThrowsExceptionWhenWrongSku() {

    // Given
    String articleSimpleSku = "999-999";
    int amountOfTransactions = 1;
    Exception exception = null;

    // When
    try {
        createNInboundTransactionsForSku(amountOfTransactions, articleSimpleSku);
    } catch (RuntimeException e) {
        exception = e;
    }

    // Then
    shouldValidateThrowsExceptionWithMessage(exception, MESSAGE_NON_EXISTENT_SKU);
}

private void shouldValidateThrowsExceptionWithMessage(final Exception e, final String message) {
    assertNotNull(e);
    assertTrue(e.getMessage().contains(message));
}

How about this: Catch a general general exception ، تأكد من أنه يخرج من كتلة catch ، ثم أكد أن صنف الاستثناء هو ما تتوقعه. سوف تفشل هذه التوكيد إذا كان a) الاستثناء من النوع الخطأ (على سبيل المثال ، إذا حصلت على Null Pointer بدلاً من ذلك) و b) لم يتم طرح الاستثناء مطلقًا.

public void testFooThrowsIndexOutOfBoundsException() {
  Throwable e = null;

  try {
    foo.doStuff();
  } catch (Throwable ex) {
    e = ex;
  }

  assertTrue(e instanceof IndexOutOfBoundsException);
}

Additionally to what has said, make sure that:

  • The ExpectedException instance is public ( Related Question )
  • The ExpectedException isn't instantiated in say, the @Before method. This post clearly explains all the intricacies of JUnit's order of execution.

Do not do this:

@Rule    
public ExpectedException expectedException;

@Before
public void setup()
{
    expectedException = ExpectedException.none();
}

Finally, this blog post clearly illustrates how to assert that a certain exception is thrown.


في الواقع ، إذا كنت تستخدم HashSet كما اقترح توم Hawtin أنك لا داعي للقلق حول الفرز والسرعة هي نفسها كما هو الحال مع Binary Search على مجموعة presorted ، ربما حتى أسرع.

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

على مجموعة غير مرتبة:

  1. HashSet
  2. asList
  3. نوع و ثنائي

على مصفوفة تم فرزها:

  1. HashSet
  2. الثنائية
  3. asList

في كلتا الحالتين ، HashSet ftw







java exception junit junit4 assert