JUnit टेस्ट एनोटेशन के साथ मैं अपने अपवाद संदेश को कैसे बताऊं?


313

मैंने @Testएनोटेशन के साथ कुछ JUnit परीक्षण लिखे हैं । यदि मेरी परीक्षा पद्धति एक अपवादित चेक को फेंकती है और यदि मैं अपवाद के साथ संदेश को मुखर करना चाहता हूं, तो क्या JUnit @Testएनोटेशन के साथ ऐसा करने का कोई तरीका है ? AFAIK, JUnit 4.7 यह सुविधा प्रदान नहीं करता है लेकिन क्या कोई भविष्य के संस्करण इसे प्रदान करते हैं? मुझे पता है कि .NET में आप संदेश और अपवाद वर्ग को मुखर कर सकते हैं। जावा दुनिया में इसी तरह की सुविधा की तलाश है।

यह वही चीज है जो मैं चाहता हूं:

@Test (expected = RuntimeException.class, message = "Employee ID is null")
public void shouldThrowRuntimeExceptionWhenEmployeeIDisNull() {}

1
अब जब मैं इसके बारे में कुछ और सोचता हूं ... क्या आपको यकीन है कि संदेश को मुखर करना एक अच्छा विचार है? आपके प्रश्न ने मुझे कनिष्ठ स्रोत कोड में थोड़ा सा खोद दिया और ऐसा लगता है कि वे इस सुविधा को आसानी से जोड़ सकते थे। तथ्य यह है कि उन्होंने नहीं किया , मुझे लगता है कि यह एक अच्छा अभ्यास नहीं माना जा सकता है। संदेश को मुखर करना आपकी परियोजना में महत्वपूर्ण क्यों है?
c_maker

9
अच्छा सवाल। यह कि कोड की 15 पंक्तियों वाली एक विधि 2 अलग-अलग स्थानों से समान अपवाद फेंकता है। मेरे परीक्षण के मामलों में केवल अपवाद वर्ग को ही नहीं बल्कि उसमें संदेश को भी शामिल करने की जरूरत है। एक आदर्श दुनिया में, किसी भी असामान्य व्यवहार का अपना अपवाद होना चाहिए। अगर ऐसा होता, तो मेरा सवाल कभी नहीं उठता, लेकिन उत्पादन अनुप्रयोगों में प्रत्येक असामान्य व्यवहार के लिए अपने विशिष्ट कस्टम अपवाद नहीं होते।
बादशाह 22'10

एक साइड नोट के रूप में - @expectedExceptionMessagePHPUnit में एनोटेशन है।
नर्तकी

जवाबों:


535

आप इस तरह से @Ruleएनोटेशन का उपयोग कर सकते हैं ExpectedException:

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

@Test
public void shouldThrowRuntimeExceptionWhenEmployeeIDisNull() throws Exception {
    expectedEx.expect(RuntimeException.class);
    expectedEx.expectMessage("Employee ID is null");

    // do something that should throw the exception...
    System.out.println("=======Starting Exception process=======");
    throw new NullPointerException("Employee ID is null");
}

ध्यान दें कि ExpectedExceptionडॉक्स में उदाहरण गलत है (वर्तमान में) - कोई सार्वजनिक निर्माता नहीं है, इसलिए आपको इसका उपयोग करना होगा ExpectedException.none()


1
नोट: मेरे लिए जब expectMessageएक खाली स्ट्रिंग के रूप में निर्दिष्ट किया गया था, तो संदेश की तुलना नहीं की गई थी
redDevil

1
मेरे लिए उपयोगी है। धन्यवाद। टेस्टमेथोड में throws RuntimeExceptionएक अपवाद फेंकने वाले कोड को जोड़ने के बाद होना चाहिए । इसे न
पकड़ें

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

2
@redDevil: अपेक्षित संदेश जांचता है कि क्या त्रुटि संदेश "इस फ़ंक्शन में निर्दिष्ट स्ट्रिंग" (त्रुटि संदेश के विकल्प के रूप में) शामिल है
tuan.dinh

3
स्ट्रिंग पैरामीटर के साथ expectMessage अपवाद संदेश उपयोग hamcrest मिलान की सटीक मिलान के लिए, एक String.contains जाँच करता हैfailure.expectMessage(CoreMatchers.equalTo(...))
सिवाबालान

41

मुझे @Ruleउत्तर पसंद है । हालाँकि, यदि किसी कारण से आप नियमों का उपयोग नहीं करना चाहते हैं। एक तीसरा विकल्प है।

@Test (expected = RuntimeException.class)
public void myTestMethod()
{
   try
   {
      //Run exception throwing operation here
   }
   catch(RuntimeException re)
   {
      String message = "Employee ID is null";
      assertEquals(message, re.getMessage());
      throw re;
    }
    fail("Employee Id Null exception did not throw!");
  }

32

क्या आपको उपयोग करना है @Test(expected=SomeException.class)? जब हमें अपवाद के वास्तविक संदेश पर जोर देना होता है, तो हम यही करते हैं।

@Test
public void myTestMethod()
{
  try
  {
    final Integer employeeId = null;
    new Employee(employeeId);
    fail("Should have thrown SomeException but did not!");
  }
  catch( final SomeException e )
  {
    final String msg = "Employee ID is null";
    assertEquals(msg, e.getMessage());
  }
}

6
मैं एक कैच ब्लॉक लिखने और उस के भीतर मुखर का उपयोग करने के बारे में जानता हूं, लेकिन बेहतर कोड पठनीयता के लिए मैं एनोटेशन के साथ करना चाहता हूं।
Cashh

इसके अलावा आपको "सही" तरीके से ऐसा अच्छा संदेश नहीं मिलेगा।
नेप्लेटनीउदज

15
ट्राय / कैच संस्करण के साथ समस्या, अब जो जुनीत प्रदान करता है @Test(expected=...)और ExpectedExceptionयह है कि मैंने कई मौकों पर देखा है कि कोई व्यक्ति कॉल को ब्लॉक fail()के अंत में रखना भूल जाता हैtry । यदि कोड समीक्षा द्वारा नहीं पकड़ा गया, तो आपका परीक्षण गलत-सकारात्मक हो सकता है और हमेशा पास हो सकता है।
विलियम प्राइस

यही कारण है कि मुझे यह सभी घोषणात्मक चीजें पसंद नहीं हैं। इससे आप जो चाहते हैं उसे एक्सेस करना मुश्किल हो जाता है।
श्रीधर सरनोबत

30

JUnit 4.13 में आप यह कर सकते हैं:

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;

...

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

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

यह JUnit 5 में भी काम करता है लेकिन विभिन्न आयातों के साथ:

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

...

इस उपाय की तरह। JUnit 5 में जाना चाहिए
पश्चिमीगुनिया

Gaaaaaaaaa। 4.13 आज भी बीटा में है (पतन, 2019)? mvnrepository.com/artifact/junit/junit
granadaCoder

v4.13 अभी बीटा स्थिति में नहीं है (जनवरी 2020 में रिलीज़)
शमौन

11

दरअसल, सबसे अच्छा उपयोग कोशिश / पकड़ के साथ है। क्यों? क्योंकि आप उस स्थान को नियंत्रित कर सकते हैं जहां आप अपवाद की अपेक्षा करते हैं।

इस उदाहरण पर विचार करें:

@Test (expected = RuntimeException.class)
public void someTest() {
   // test preparation
   // actual test
}

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

यही कारण है कि एनोटेशन पर भरोसा करने की तुलना में कोशिश / पकड़ का उपयोग करना बेहतर है।


अफसोस की बात है, यह मेरा भी जवाब है।
श्रीधर सरनोबत

2
छोटे, क्रमपरिवर्तन-विशिष्ट परीक्षण मामलों के होने से कोड परिवर्तन संबंधी चिंताओं को दूर किया जाता है। कभी-कभी यह अपरिहार्य होता है और हमें कैच / ट्राई मेथड पर निर्भर रहना पड़ता है, लेकिन अगर ऐसा अक्सर होता है, तो संभावना है कि हमें अपने टेस्ट केस फंक्शन लिखने के तरीके को संशोधित करने की आवश्यकता है।
luis.espinal

यह आपके परीक्षण और / या कोड के साथ एक समस्या है। आप एक सामान्य RuntimeException की उम्मीद नहीं करते हैं, आप एक विशिष्ट अपवाद की उम्मीद करते हैं, या बहुत कम से कम एक विशिष्ट संदेश।
डेनिसके

मैंने RuntimeExceptionएक उदाहरण के रूप में उपयोग किया , इस अपवाद को किसी अन्य अपवाद के साथ बदलें।
क्रिज़ीस्तोफ़ सिस्लो

8

रेस्टॉर्म का अच्छा जवाब था। मैं नियमों का बहुत बड़ा प्रशंसक नहीं हूं। मैं ऐसा ही कुछ करता हूं, सिवाय इसके कि मैं पठनीयता और प्रयोज्यता में मदद करने के लिए निम्नलिखित उपयोगिता वर्ग बनाता हूं, जो पहले स्थान पर एनोटेशन के बड़े प्लसस में से एक है।

इस उपयोगिता वर्ग को जोड़ें:

import org.junit.Assert;

public abstract class ExpectedRuntimeExceptionAsserter {

    private String expectedExceptionMessage;

    public ExpectedRuntimeExceptionAsserter(String expectedExceptionMessage) {
        this.expectedExceptionMessage = expectedExceptionMessage;
    }

    public final void run(){
        try{
            expectException();
            Assert.fail(String.format("Expected a RuntimeException '%s'", expectedExceptionMessage));
        } catch (RuntimeException e){
            Assert.assertEquals("RuntimeException caught, but unexpected message", expectedExceptionMessage, e.getMessage());
        }
    }

    protected abstract void expectException();

}

फिर मेरी इकाई परीक्षण के लिए, मुझे केवल इस कोड की आवश्यकता है:

@Test
public void verifyAnonymousUserCantAccessPrivilegedResourceTest(){
    new ExpectedRuntimeExceptionAsserter("anonymous user can't access privileged resource"){
        @Override
        protected void expectException() {
            throw new RuntimeException("anonymous user can't access privileged resource");
        }
    }.run(); //passes test; expected exception is caught, and this @Test returns normally as "Passed"
}

2

यदि @ नियम का उपयोग किया जाता है, तो परीक्षण कक्षा में सभी परीक्षण विधियों पर अपवाद सेट लागू होता है।


2
जेसी मेरिमन प्रतिक्रिया का उपयोग करते हुए, अपवाद केवल परीक्षण विधियों में जांचा जाता है जो अपेक्षितEx.expect () और अपेक्षितEx.expectMessage () पर कॉल करते हैं। अन्य विधियाँ अपेक्षानुसार परिभाषा का प्रयोग करेगी। ExpectedException.none (), अर्थात कोई अपवाद अपेक्षित नहीं है।
ईगल

2

मुझे जुनैद के साथ अपवादों को स्वीकार करने का तरीका कभी पसंद नहीं आया। यदि मैं एनोटेशन में "अपेक्षित" का उपयोग करता हूं, तो मेरे दृष्टिकोण से लगता है कि हम "दिए गए, कब, तो" पैटर्न का उल्लंघन कर रहे हैं क्योंकि "फिर" को परीक्षण परिभाषा के शीर्ष पर रखा गया है।

इसके अलावा, यदि हम "@ नियम" का उपयोग करते हैं, तो हमें बहुत सारे बॉयलरप्लेट कोड से निपटना होगा। इसलिए, यदि आप अपने परीक्षणों के लिए नई लाइब्रेरी स्थापित कर सकते हैं, तो मैं आपको AssertJ (कि लाइब्रेरी अब स्प्रिंगस्टॉक के साथ आता है) पर एक नज़र डालने का सुझाव दूंगा

फिर एक परीक्षण जो "दिए गए / जब / तब" सिद्धांतों का उल्लंघन नहीं कर रहा है, और यह सत्यापित करने के लिए AssertJ का उपयोग किया जाता है:

1 - अपवाद वह है जो हम उम्मीद कर रहे हैं। 2 - इसमें एक अपेक्षित संदेश भी है

इस तरह दिखेगा:

 @Test
void should_throwIllegalUse_when_idNotGiven() {

    //when
    final Throwable raisedException = catchThrowable(() -> getUserDAO.byId(null));

    //then
    assertThat(raisedException).isInstanceOf(IllegalArgumentException.class)
            .hasMessageContaining("Id to fetch is mandatory");
}

1

मुझे user64141 का उत्तर पसंद है लेकिन यह पाया कि इसे और अधिक सामान्यीकृत किया जा सकता है। यहाँ मेरा ले रहा है:

public abstract class ExpectedThrowableAsserter implements Runnable {

    private final Class<? extends Throwable> throwableClass;
    private final String expectedExceptionMessage;

    protected ExpectedThrowableAsserter(Class<? extends Throwable> throwableClass, String expectedExceptionMessage) {
        this.throwableClass = throwableClass;
        this.expectedExceptionMessage = expectedExceptionMessage;
    }

    public final void run() {
        try {
            expectException();
        } catch (Throwable e) {
            assertTrue(String.format("Caught unexpected %s", e.getClass().getSimpleName()), throwableClass.isInstance(e));
            assertEquals(String.format("%s caught, but unexpected message", throwableClass.getSimpleName()), expectedExceptionMessage, e.getMessage());
            return;
        }
        fail(String.format("Expected %s, but no exception was thrown.", throwableClass.getSimpleName()));
    }

    protected abstract void expectException();

}

ध्यान दें कि कोशिश ब्लॉक के भीतर "असफल" बयान छोड़ने से संबंधित जोर अपवाद को पकड़ा जाता है; कैच स्टेटमेंट के भीतर रिटर्न का उपयोग करना इसे रोकता है।


0

कैच-अपवाद लाइब्रेरी आयात करें , और उसका उपयोग करें। यह ExpectedExceptionनियम या ए की तुलना में बहुत साफ है try-catch

उदाहरण उनके डॉक्स बनाते हैं:

import static com.googlecode.catchexception.CatchException.*;
import static com.googlecode.catchexception.apis.CatchExceptionHamcrestMatchers.*;

// given: an empty list
List myList = new ArrayList();

// when: we try to get the first element of the list
catchException(myList).get(1);

// then: we expect an IndexOutOfBoundsException with message "Index: 1, Size: 0"
assertThat(caughtException(),
  allOf(
    instanceOf(IndexOutOfBoundsException.class),
    hasMessage("Index: 1, Size: 0"),
    hasNoCause()
  )
);

-2
@Test (expectedExceptions = ValidationException.class, expectedExceptionsMessageRegExp = "This is not allowed")
public void testInvalidValidation() throws Exception{
     //test code
}

क्या कोई मुझे यह समझने में मदद कर सकता है कि यह उत्तर क्यों -1 है
आषाढ़

सवाल पूछ रहा है, Junitलेकिन उर जवाब दे रहा हैTestNG
हुज़े यिन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.