java - आप कैसे कहते हैं कि जुनीट 4 परीक्षणों में एक निश्चित अपवाद फेंक दिया गया है?




exception junit (20)

मैं परीक्षण करने के लिए junit4 idiomatically कैसे उपयोग कर सकता हूं कि कुछ कोड अपवाद फेंकता है?

जबकि मैं निश्चित रूप से ऐसा कुछ कर सकता हूं:

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

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

  assertTrue(thrown);
}

मुझे याद है कि इस तरह की स्थितियों के लिए जुनीट की भावना बहुत कम है और एक ऐसी चीज है जो Assert.xyz या कुछ है जो बहुत कम है।


जावा 8 समाधान

यदि आप एक समाधान चाहते हैं जो:

  • जावा 8 लैम्बडा का उपयोग करता है
  • किसी भी जुनीट जादू पर निर्भर नहीं है
  • आपको एक एकल परीक्षण विधि के भीतर कई अपवादों की जांच करने की अनुमति देता है
  • संपूर्ण परीक्षण विधि में किसी भी अज्ञात रेखा के बजाय आपकी परीक्षण विधि के भीतर लाइनों के विशिष्ट सेट द्वारा फेंकने वाले अपवाद के लिए जांच करता है
  • वास्तविक अपवाद वस्तु उत्पन्न करता है जिसे फेंक दिया गया ताकि आप इसे और जांच सकें

यहां एक उपयोगिता कार्य है जिसे मैंने लिखा था:

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!" );
}

जुनीट 5 समाधान

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

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

Http://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions पर जुनीट 5 के बारे में अधिक जानकारी


अपेक्षित अपवाद का उपयोग करके सावधान रहें, क्योंकि यह केवल यह दावा करता है कि विधि ने उस अपवाद को फेंक दिया, परीक्षण में कोड की एक विशेष पंक्ति नहीं।

मैं पैरामीटर सत्यापन के परीक्षण के लिए इसका उपयोग करता हूं, क्योंकि ऐसी विधियां आमतौर पर बहुत ही सरल होती हैं, लेकिन अधिक जटिल परीक्षणों के साथ बेहतर तरीके से सेवा की जा सकती है:

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

निर्णय लागू करें।


अब संपादित करें कि JUnit5 जारी किया गया है, सबसे अच्छा विकल्प Assertions.assertThrows() का उपयोग करना होगा ( मेरा अन्य उत्तर देखें)।

यदि आप जुनीट 5 में माइग्रेट नहीं हुए हैं, लेकिन जुनीट 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) से काफी बेहतर है क्योंकि परीक्षण विफल हो जाएगा यदि IndexOutOfBoundsException foo.doStuff() से पहले फेंक दिया गया है

विवरण के लिए यह आलेख देखें


आईएमएचओ, जुनीट में अपवादों की जांच करने का सबसे अच्छा तरीका है कोशिश / पकड़ / असफल / जोरदार पैटर्न:

// this try block should be as small as possible,
// as you want to make sure you only catch exceptions from your code
try {
    sut.doThing();
    fail(); // fail if this does not throw any exception
} catch(MyException e) { // only catch the exception you expect,
                         // otherwise you may catch an exception for a dependency unexpectedly
    // a strong assertion on the message, 
    // in case the exception comes from anywhere an unexpected line of code,
    // especially important if your checking IllegalArgumentExceptions
    assertEquals("the message I get", e.getMessage()); 
}

assertTrue कुछ लोगों के लिए थोड़ा मजबूत हो सकता है, इसलिए assertThat(e.getMessage(), containsString("the message"); बेहतर हो सकता है।


आप यह भी कर सकते हैं:

@Test
public void testFooThrowsIndexOutOfBoundsException() {
    try {
        foo.doStuff();
        assert false;
    } catch (IndexOutOfBoundsException e) {
        assert true;
    }
}

एक AssertJ दावे का उपयोग करना, जिसका उपयोग JUnit के साथ किया जा सकता है:

import static org.assertj.core.api.Assertions.*;

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

  assertThatThrownBy(() -> foo.doStuff())
        .isInstanceOf(IndexOutOfBoundsException.class);
}

यह @Test(expected=IndexOutOfBoundsException.class) से बेहतर है क्योंकि यह परीक्षण में अपेक्षित रेखा की गारंटी देता है अपवाद फेंक देता है और आपको अपवाद के बारे में अधिक जानकारी देता है, जैसे संदेश, आसान:

assertThatThrownBy(() ->
       {
         throw new Exception("boom!");
       })
    .isInstanceOf(Exception.class)
    .hasMessageContaining("boom");

मेवेन / ग्रैडल निर्देश यहां।


एक ही समस्या को हल करने के लिए मैंने एक छोटी परियोजना स्थापित की: http://code.google.com/p/catch-exception/

इस छोटे से सहायक का उपयोग करके आप लिखेंगे

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

यह जुनीट 4.7 के अपेक्षित अपवाद नियम से कम वर्बोज़ है। स्काफमैन द्वारा प्रदान किए गए समाधान की तुलना में, आप निर्दिष्ट कर सकते हैं कि आप किस कोड की अपवाद अपवाद की अपेक्षा करते हैं। आशा है कि ये आपकी मदद करेगा।


जुनीट 4 या बाद में आप अपवादों का परीक्षण निम्नानुसार कर सकते हैं

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


this provides a lot of features which can be used to improve our JUnit tests.
If you see the below example I am testing 3 things on the exception.

  1. The Type of exception thrown
  2. The exception Message
  3. The cause of the exception


public class MyTest {

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

    ClassUnderTest classUnderTest;

    @Before
    public void setUp() throws Exception {
        classUnderTest = new ClassUnderTest();
    }

    @Test
    public void testAppleisSweetAndRed() throws Exception {

        exceptions.expect(Exception.class);
        exceptions.expectMessage("this is the exception message");
        exceptions.expectCause(Matchers.<Throwable>equalTo(exceptionCause));

        classUnderTest.methodUnderTest("param1", "param2");
    }

}


जैसा कि पहले उत्तर दिया गया था, जुनीट में अपवादों से निपटने के कई तरीके हैं। लेकिन जावा 8 के साथ एक और है: लैम्ब्डा अभिव्यक्तियों का उपयोग करना। लैम्ब्डा अभिव्यक्तियों के साथ हम इस तरह एक वाक्यविन्यास प्राप्त कर सकते हैं:

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

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

प्रकटीकरण: मैं ब्लॉग और परियोजना का लेखक हूं।


मेरे मामले में मुझे हमेशा डीबी से रनटाइम अपवाद मिलता है, लेकिन संदेश अलग-अलग होते हैं। और अपवाद को क्रमशः संभालने की आवश्यकता है। यहां बताया गया है कि मैंने इसका परीक्षण कैसे किया:

@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));
}

tl; डॉ

  • प्री-जेडीके 8: मैं पुराने अच्छे try - catch ब्लॉक try सिफारिश करूंगा।

  • जेडीके 8 के बाद: असाधारण व्यवहार का दावा करने के लिए AssertJ या कस्टम lambdas का उपयोग करें।

लंबी कहानी

अपने आप को लिखना संभव है कि यह स्वयं को try - ब्लॉक को @Rule ExpectedException या @Test(expected = ...) टूल्स ( @Test(expected = ...) या @Rule ExpectedException JUnit नियम सुविधा का उपयोग करें)।

लेकिन इस तरह से इतने सुरुचिपूर्ण नहीं हैं और अन्य उपकरणों के साथ अच्छी तरह से पठनीयता के साथ मिश्रण नहीं करते हैं।

  1. try - catch ब्लॉक आपको परीक्षण किए गए व्यवहार के चारों ओर ब्लॉक लिखना है, और पकड़ ब्लॉक में दावा लिखना है, जो ठीक हो सकता है लेकिन कई लोग इस शैली को एक परीक्षण के पढ़ने के प्रवाह में बाधा डालते हैं। इसके अलावा आपको try ब्लॉक के अंत में एक Assert.fail लिखना होगा अन्यथा परीक्षण दावे के एक तरफ से चूक सकता है; पीएमडी , फाइंडबग या सोनार ऐसे मुद्दों को खोजेंगे

  2. @Test(expected = ...) सुविधा दिलचस्प है क्योंकि आप कम कोड लिख सकते हैं और फिर यह परीक्षण लिखना त्रुटियों को कोडिंग के लिए कम प्रवण होता है। लेकिन वें दृष्टिकोण में कुछ क्षेत्रों की कमी है।

    • यदि परीक्षण को कारण या संदेश जैसे अपवाद पर अतिरिक्त चीजों की जांच करने की आवश्यकता है (अच्छे अपवाद संदेश वास्तव में महत्वपूर्ण हैं, तो सटीक अपवाद प्रकार पर्याप्त नहीं हो सकता है)।
    • साथ ही विधि में अपेक्षा की जाती है, परीक्षण कोड कैसे लिखा जाता है, इस पर निर्भर करता है कि परीक्षण कोड का गलत हिस्सा अपवाद फेंक सकता है, जिससे झूठी सकारात्मक परीक्षा होती है और मुझे यकीन नहीं है कि पीएमडी , ढूंढने या सोनार दे देंगे इस तरह के कोड पर संकेत।

      @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 उपयोगकर्ता इस शैली को बहुत अच्छी तरह से जानते हैं। यह कुछ के लिए सुविधाजनक हो सकता है, लेकिन यदि आप व्यवहार संचालित विकास (बीडीडी) या अधिनियम अधिनियम (एएए) सिद्धांतों का पालन करते हैं तो ExpectedException नियम उन लेखन शैली में फिट नहीं होगा। इसके अलावा यह एक ही मुद्दे से @Test रास्ता के रूप में @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
    }
    

    यहां तक ​​कि अपेक्षित अपवाद परीक्षण विवरण से पहले रखा गया है, यदि परीक्षण बीडीडी या एएए का पालन करते हैं तो यह आपके पढ़ने के प्रवाह को तोड़ देता है।

    ExpectException के लेखक के जुनीट पर यह comment समस्या भी देखें।

तो इन उपरोक्त विकल्पों में उनके सभी गुफाओं का भार है, और स्पष्ट रूप से कोडर त्रुटियों से प्रतिरक्षा नहीं है।

  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 एपीआई एक उपनाम है जो AssertJ API का उपयोग assertThat(ex).hasNoCause()... का उपयोग करने के समान। assertThat(ex).hasNoCause()... )। कुछ बिंदु पर परियोजना ने एस्टेस्टजे के पूर्वजों को फेस्ट-एसेर्ट पर भरोसा कियासंपादित करें: ऐसा लगता है कि यह प्रोजेक्ट जावा 8 लैम्ब्डा समर्थन बना रहा है।

    वर्तमान में इस पुस्तकालय में दो कमियां हैं:

    • इस लेखन के समय यह कहना उचित है कि यह लाइब्रेरी Mockito 1.x पर आधारित है क्योंकि यह दृश्य के पीछे परीक्षण वस्तु का एक नकली बनाता है। चूंकि मॉकिटो अभी भी अपडेट नहीं हुआ है, इसलिए यह लाइब्रेरी अंतिम कक्षाओं या अंतिम विधियों के साथ काम नहीं कर सकती है । और यहां तक ​​कि यदि यह मौजूदा संस्करण में मॉकिटो 2 पर आधारित था, तो उसे ग्लोबल मॉक मेकर ( inline-mock-maker ) घोषित करने की आवश्यकता होगी, जो कुछ भी आप नहीं चाहते हैं, क्योंकि इस मॉकमेकर में नियमित रूप से मॉकमेकर की अलग-अलग कमीएं होती हैं।

    • इसके लिए अभी तक एक और परीक्षण निर्भरता की आवश्यकता है।

    लाइब्रेडा का समर्थन करने के बाद ये समस्याएं लागू नहीं होंगी, हालांकि कार्यक्षमता AssertJ टूलसेट द्वारा डुप्लिकेट की जाएगी।

    यदि आप कैच-अपवाद टूल का उपयोग नहीं करना चाहते हैं तो सभी को ध्यान में रखते हुए, मैं कम से कम जेडीके 7 तक try - catch ब्लॉक के पुराने अच्छे तरीके की सिफारिश करूंगा। और जेडीके 8 उपयोगकर्ताओं के लिए आप एस्र्टजे का उपयोग करना पसंद कर सकते हैं क्योंकि यह ऑफ़र अपवादों के मुकाबले ज्यादा हो सकता है।

  2. जेडीके 8 के साथ, लैम्बडास परीक्षण दृश्य में प्रवेश करते हैं, और वे असाधारण व्यवहार का दावा करने के लिए एक दिलचस्प तरीका साबित हुए हैं। असाधारण व्यवहार का दावा करने के लिए AssertJ को एक अच्छा धाराप्रवाह API प्रदान करने के लिए अद्यतन किया गया है।

    और 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. जुनीट 5 के पास पूरी तरह से पुनर्लेखन के साथ, दावों में थोड़ा improved है, वे सही तरीके से अपवाद लगाने के लिए बॉक्स के रास्ते के रूप में दिलचस्प साबित हो सकते हैं। लेकिन वास्तव में दावा एपीआई अभी भी थोड़ा खराब है, वहाँ assertThrows बाहर कुछ भी नहीं है।

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

    जैसा कि आपने देखा है कि assertEquals अभी भी void लौट रहा void , और इस तरह AssertJ जैसे चेनिंग दावे की अनुमति नहीं है।

    अगर आपको Matcher या Assert के साथ नाम टकराव याद है, तो Assertions के साथ एक ही संघर्ष को पूरा करने के लिए तैयार रहें।

मैं यह निष्कर्ष निकालना चाहता हूं कि आज (2017-03-03) आर्टर्टजे की आसानी, उपयोग करने योग्य एपीआई, विकास की तीव्र गति और एक वास्तविक तथ्य निर्भरता के रूप में परीक्षण ढांचे के बावजूद जेडीके 8 के साथ सबसे अच्छा समाधान है (जुनीट या नहीं), पूर्व जेडीके को बदले में catch ब्लॉक पर भरोसा करना चाहिए, भले ही वे गुंजाइश महसूस करें।

यह उत्तर किसी अन्य प्रश्न से कॉपी किया गया है जिसमें समान दृश्यता नहीं है, मैं वही लेखक हूं।


अद्यतन: JUnit5 में अपवाद परीक्षण के लिए एक सुधार है: assertThrows

निम्नलिखित उदाहरण है: जूनिट 5 उपयोगकर्ता मार्गदर्शिका

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

जुनीट 4 का उपयोग कर मूल जवाब।

परीक्षण करने के कई तरीके हैं कि एक अपवाद फेंक दिया गया है। मैंने अपनी पोस्ट में नीचे दिए गए विकल्पों पर भी चर्चा की है जो जुनीट के साथ महान यूनिट परीक्षण कैसे लिखें

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");
}

आप अपवाद परीक्षण और bad.robot के लिए JUnit4 विकी में अपवाद परीक्षण के बारे में अधिक पढ़ सकते हैं - अपवादों की अपेक्षा JUnit नियम


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);
}

Junit4 solution with Java8 is to use this function:

public Throwable assertThrows(Class<? extends Throwable> expectedException, java.util.concurrent.Callable<?> funky) {
    try {
        funky.call();
    } catch (Throwable e) {
        if (expectedException.isInstance(e)) {
            return e;
        }
        throw new AssertionError(
                String.format("Expected [%s] to be thrown, but was [%s]", expectedException, e));
    }
    throw new AssertionError(
            String.format("Expected [%s] to be thrown, but nothing was thrown.", expectedException));
}

Usage is then:

    assertThrows(ValidationException.class,
            () -> finalObject.checkSomething(null));

Note that the only limitation is to use a final object reference in lambda expression. This solution allows to continue test assertions instead of expecting thowable at method level using @Test(expected = IndexOutOfBoundsException.class) solution.


My solution using Java 8 lambdas:

public static <T extends Throwable> T assertThrows(Class<T> expected, ThrowingRunnable action) throws Throwable {
    try {
        action.run();
        Assert.fail("Did not throw expected " + expected.getSimpleName());
        return null; // never actually
    } catch (Throwable actual) {
        if (!expected.isAssignableFrom(actual.getClass())) { // runtime '!(actual instanceof expected)'
            System.err.println("Threw " + actual.getClass().getSimpleName() 
                               + ", which is not a subtype of expected " 
                               + expected.getSimpleName());
            throw actual; // throw the unexpected Throwable for maximum transparency
        } else {
            return (T) actual; // return the expected Throwable for further examination
        }
    }
}

You have to define a FunctionalInterface, because Runnable doesn't declare the required throws .

@FunctionalInterface
public interface ThrowingRunnable {
    void run() throws Throwable;
}

The method can be used as follows:

class CustomException extends Exception {
    public final String message;
    public CustomException(final String message) { this.message = message;}
}
CustomException e = assertThrows(CustomException.class, () -> {
    throw new CustomException("Lorem Ipsum");
});
assertEquals("Lorem Ipsum", e.message);

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"});
}

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...


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());
}




assert