كيف أؤكد رسالتي الاستثناء من خلال تعليق توضيح اختبار Junit؟

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

سؤال

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

هذا ما أريده:

@Test (expected = RuntimeException.class, message = "Employee ID is null")
public void shouldThrowRuntimeExceptionWhenEmployeeIDisNull() {}
هل كانت مفيدة؟

المحلول

يمكنك استخدام @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().

نصائح أخرى

انا احب ال @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!");
  }

هل يجب أن تستخدم @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());
  }
}

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

هذا يعمل أيضا في جونيت 5 ولكن مع واردات مختلفة:

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

...

في الواقع ، أفضل استخدام هو مع Try/Catch. لماذا ا؟ لأنه يمكنك التحكم في المكان الذي تتوقع فيه الاستثناء.

النظر في هذا المثال:

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

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

هذا هو السبب في أنه من الأفضل استخدام Try/Catch بدلاً من الاعتماد على التعليقات التوضيحية.

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

أضف فئة الأداة المساعدة هذه:

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

في حالة استخدام @Rule ، يتم تطبيق مجموعة الاستثناء على جميع طرق الاختبار في فئة الاختبار.

أحب إجابة 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();

}

لاحظ أن ترك بيان "FAIL" داخل كتلة المحاولة يتسبب في استثناء التأكيد ذي الصلة. باستخدام العودة ضمن بيان الصيد يمنع هذا.

استيراد استثمار مكتبة ، واستخدم ذلك. إنه أكثر نظافة من 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()
  )
);
@Test (expectedExceptions = ValidationException.class, expectedExceptionsMessageRegExp = "This is not allowed")
public void testInvalidValidation() throws Exception{
     //test code
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top