문제

JUnit4를 관용적으로 사용하여 일부 코드에서 예외가 발생하는지 테스트하려면 어떻게 해야 합니까?

확실히 다음과 같은 작업을 수행할 수 있습니다.

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

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

  assertTrue(thrown);
}

주석이나 Assert.xyz 또는 무엇 이러한 종류의 상황에 대해서는 훨씬 덜 복잡하고 훨씬 더 JUnit의 정신에 가깝습니다.

도움이 되었습니까?

해결책

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) 테스트가 실패하기 때문에 IndexOutOfBoundsException 전에 던져졌습니다 foo.doStuff()

보다 이 기사 자세한 내용은

예상 예외를 사용하여 조심하십시오. 방법 그 예외는 아니었다 특정 코드 라인 시험에서.

테스트 매개 변수 검증에 이것을 사용하는 경향이 있습니다. 이러한 방법은 일반적으로 매우 간단하지만 더 복잡한 테스트는 다음과 같이 더 잘 제공 될 수 있기 때문입니다.

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

판단을 적용하십시오.

이전에 답한 바와 같이, Junit의 예외를 다루는 방법에는 여러 가지가 있습니다. 그러나 Java 8에는 Lambda Expressions 사용이 있습니다. 람다 표현식으로 우리는 다음과 같은 구문을 달성 할 수 있습니다.

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

Assertrown은 기능적 인터페이스를 수용하며 Lambda 표현식, 메소드 참조 또는 생성자 참조로 인스턴스를 만들 수 있습니다. Assertrown은 그 인터페이스를 받아들이는 것이 예외를 기대하고 처리 할 준비가되어있을 것입니다.

이것은 비교적 간단하지만 강력한 기술입니다.

이 기술을 설명하는이 블로그 게시물을 살펴보십시오. 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

공개 : 저는 블로그와 프로젝트의 저자입니다.

Junit에는 예외를 테스트하는 4 가지 방법이 있습니다.

  • junit4.x의 경우 테스트 Annonation의 선택적 '예상'속성을 사용하십시오.

    @Test(expected = IndexOutOfBoundsException.class)
    public void testFooThrowsIndexOutOfBoundsException() {
        foo.doStuff();
    }
    
  • junit4.x의 경우 expectexception 규칙을 사용하십시오

    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.
        }
    }
    
  • 마지막으로 Junit5.x의 경우 AssertThrows를 다음과 같이 사용할 수도 있습니다.

    @Test
    public void testFooThrowsIndexOutOfBoundsException() {
        Throwable exception = assertThrows(IndexOutOfBoundsException.class, () -> foo.doStuff());
        assertEquals("expected messages", exception.getMessage());
    }
    
  • 그래서

    • 첫 번째 방법은 예외 유형을 테스트 할 때만 사용됩니다.
    • 다른 세 가지 방법은 테스트 예외 메시지를 더 원할 때 사용됩니다.
    • Junit 3을 사용하면 3 번째가 선호됩니다.
    • Junit 5를 좋아한다면 네 번째를 좋아해야합니다.
  • 자세한 내용은 읽을 수 있습니다 이 문서 그리고 Junit5 사용자 안내서 자세한 내용은.

tl;dr

  • JDK8 이전 :오래된거 추천해줄게 try-catch 차단하다.(추가하는 것을 잊지 마세요 fail() 앞선 주장 catch 차단하다)

  • JDK8 이후 :AssertJ 또는 사용자 정의 람다를 사용하여 어설션 특별한 행동.

Junit 4 또는 JUnit 5에 관계없이.

긴 이야기

본인이 직접 작성하는 것이 가능합니다 너 스스로해라 try-catch 차단하거나 JUnit 도구(@Test(expected = ...) 아니면 그 @Rule ExpectedException JUnit 규칙 기능).

하지만 이 방법은 그다지 우아하지도 않고 잘 섞이지도 않습니다. 가독성이 현명한 다른 도구로.게다가 JUnit 도구에는 몇 가지 함정이 있습니다.

  1. 그만큼 try-catch block 테스트된 동작 주위에 블록을 작성하고 catch 블록에 어설션을 작성해야 합니다. 이는 괜찮을 수 있지만 많은 사람들이 이 스타일이 테스트 읽기 흐름을 방해한다고 생각합니다.또한 당신은 Assert.fail 의 끝에서 try 차단하지 않으면 테스트에서 주장의 한 측면을 놓칠 수 있습니다. PMD, 버그 찾기 또는 소나 그러한 문제를 발견하게 될 것입니다.

  2. 그만큼 @Test(expected = ...) 이 기능은 더 적은 수의 코드를 작성할 수 있고 이 테스트를 작성하면 코딩 오류가 발생할 가능성이 적다는 점에서 흥미롭습니다. 하지만 이 접근 방식에는 일부 영역이 부족합니다.

    • 테스트에서 원인이나 메시지와 같은 예외에 대한 추가 사항을 확인해야 하는 경우(좋은 예외 메시지는 정말 중요하며 정확한 예외 유형을 갖는 것만으로는 충분하지 않을 수 있습니다)
    • 또한 메서드 주변에 기대치가 있으므로 테스트된 코드가 어떻게 작성되었는지에 따라 테스트 코드의 잘못된 부분에서 예외가 발생하여 거짓 긍정 테스트가 발생할 수 있으며 확실하지 않습니다. PMD, 버그 찾기 또는 소나 해당 코드에 대한 힌트를 제공합니다.

      @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 rule 역시 이전의 주의사항을 수정하려는 시도이지만 예상 스타일을 사용하기 때문에 사용하기에는 약간 어색한 느낌이 듭니다. EasyMock 사용자들은 이 스타일을 아주 잘 알고 있습니다.누군가에게는 편리할 수도 있지만, 따라해 보면 행동 중심 개발 (BDD) 또는 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를 따르면 읽기 흐름이 중단됩니다.

    이것도 보세요 논평 작성자의 JUnit 문제 ExpectedException. JUnit 4.13-베타-2 심지어 이 메커니즘을 더 이상 사용하지 않습니다.

    풀 리퀘스트 #1519:ExpectedException 지원 중단

    Assert.assertThrows 메소드는 예외를 확인하는 더 좋은 방법을 제공합니다.또한 규칙의 순서가 중요하기 때문에 TestWatcher와 같은 다른 규칙과 함께 사용할 경우 ExpectedException을 사용하면 오류가 발생하기 쉽습니다.

따라서 위의 옵션에는 많은 경고 사항이 있으며 분명히 코더 오류로부터 면역되지 않습니다.

  1. 유망해 보이는 이 답변을 만든 후 알게 된 프로젝트가 있습니다. 캐치 예외.

    프로젝트 설명에 따르면 코더는 예외를 포착하는 유창한 코드 라인을 작성하고 나중에 어설션을 위해 이 예외를 제공할 수 있습니다.그리고 다음과 같은 어설션 라이브러리를 사용할 수 있습니다. 햄크레스트 또는 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 API를 사용하는 별칭입니다(사용하는 것과 유사). assertThat(ex).hasNoCause()...). 어느 시점에서 프로젝트는 AssertJ의 조상인 FEST-Assert에 의존했습니다.. 편집하다: 프로젝트가 Java 8 Lambda 지원을 준비하고 있는 것 같습니다.

    현재 이 라이브러리에는 두 가지 단점이 있습니다.

    • 이 글을 쓰는 시점에서 이 라이브러리는 Mockito 1.x를 기반으로 하며 장면 뒤에서 테스트된 개체의 모의를 생성한다는 점은 주목할 만합니다.Mockito가 아직 업데이트되지 않았기 때문에 이 라이브러리는 최종 클래스 또는 최종 메서드와 함께 작동할 수 없습니다..그리고 현재 버전에서 mockito 2를 기반으로 했다고 하더라도 전역 모의 제작자를 선언해야 합니다(inline-mock-maker), 이 모의 제작자는 일반 모의 제작자와 다른 단점을 갖고 있기 때문에 원하는 것이 아닐 수도 있습니다.

    • 또 다른 테스트 종속성이 필요합니다.

    라이브러리가 람다를 지원하면 이러한 문제는 적용되지 않지만 해당 기능은 AssertJ 도구 세트에 의해 복제됩니다.

    catch 예외 도구를 사용하고 싶지 않은 경우 모든 것을 고려하여 이전의 좋은 방법을 권장합니다. try-catch 블록, 최소한 JDK7까지.그리고 JDK 8 사용자의 경우 AssertJ를 사용하는 것이 더 나을 수 있습니다. 이는 단순히 예외를 주장하는 것 이상의 기능을 제공하기 때문입니다.

  2. JDK8을 사용하면 람다가 테스트 장면에 들어가며 예외적인 동작을 주장하는 흥미로운 방법임이 입증되었습니다.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. JUnit 5를 거의 완전히 재작성하여 주장은 다음과 같습니다. 향상 약간, 그들은 적절하게 예외를 주장하는 독창적인 방법으로 흥미로울 수 있습니다.하지만 실제로 어설션 API는 여전히 약간 열악합니다. 외부에는 아무것도 없습니다. assertThrows.

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

    당신이 알아 차린대로 assertEquals 아직도 돌아오고 있어요 void, 따라서 AssertJ와 같은 연결 어설션을 허용하지 않습니다.

    또한 이름이 다음과 충돌하는 것을 기억한다면 Matcher 또는 Assert, 동일한 충돌에 직면할 준비를 하십시오. Assertions.

오늘은 (2017-03-03) 이렇게 결론을 내리고 싶습니다. AssertJ의 사용 용이성, 검색 가능한 API, 빠른 개발 속도 및 사실상 테스트 종속성은 테스트 프레임워크(JUnit 여부)에 관계없이 JDK8을 사용하는 최상의 솔루션입니다. 이전 JDK는 대신 다음 항목에 의존해야 합니다. try-catch 투박한 느낌이 들더라도 차단하세요.

이 답변은 다음에서 복사되었습니다. 다른 질문 가시성이 동일하지 않은 경우에도 저는 동일한 작성자입니다.

Junit 5가 출시되었으므로 최선의 선택은 사용하는 것입니다. Assertions.assertThrows() (참조 Junit 5 사용자 안내서).

다음은 예외가 발생하고 사용하는 예입니다. 진실 예외 메시지에 대한 주장을하기 위해 :

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

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

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

다른 답변의 접근 방식에 대한 장점은 다음과 같습니다.

  1. 주니트에 내장
  2. Lambda의 코드가 예외를 던지지 않으면 유용한 예외 메시지가 표시되고 다른 예외가 발생하는 경우 StackTrace가 있습니다.
  3. 간결한
  4. 테스트가 배열-액트-어스 트를 따를 수 있습니다
  5. 예외를 던질 것으로 예상되는 코드를 정확하게 표시 할 수 있습니다.
  6. 예상 예외를 throws
  7. 선택한 Assertion Framework를 사용하여 잡힌 예외에 대한 어설 션을 할 수 있습니다.

비슷한 방법이 추가됩니다 org.junit Assert Junit 4.13에서.

어떻게 : 매우 일반적인 예외를 잡으십시오. 캐치 블록에서 벗어나게 한 다음 예외의 클래스가 당신이 기대하는 것이라고 주장하십시오. a) 예외가 잘못된 유형 (예 : 널 포인터를 대신 한 경우)과 b) 예외가 발생하지 않은 경우이 주장은 실패합니다.

public void testFooThrowsIndexOutOfBoundsException() {
  Throwable e = null;

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

  assertTrue(e instanceof IndexOutOfBoundsException);
}

BDD 스타일 솔루션 : 주니트 4 + 예외를 잡습니다 + Assertj

@Test
public void testFooThrowsIndexOutOfBoundsException() {

    when(foo).doStuff();

    then(caughtException()).isInstanceOf(IndexOutOfBoundsException.class);

}

소스 코드

의존성

eu.codearte.catch-exception:catch-exception:1.3.3

사용 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");

Maven/Gradle 지침은 여기에 있습니다.

동일한 문제를 해결하기 위해 작은 프로젝트를 설정했습니다.http://code.google.com/p/catch-exception/

이 작은 도우미를 사용하여 글을 쓸 것입니다

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

이것은 Junit 4.7의 expectionException 규칙보다 덜 장점입니다. Skaffman이 제공하는 솔루션과 비교하여 예외를 기대하는 코드 라인을 지정할 수 있습니다. 이게 도움이 되길 바란다.

업데이트: 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.

당신은 또한 이것을 할 수 있습니다 :

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

IMHO, Junit의 예외를 확인하는 가장 좋은 방법은 Try/Catch/Fail/Assert 패턴입니다.

// 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"); 바람직 할 수 있습니다.

Junit 5 솔루션

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

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

Junit 5 ON에 대한 더 많은 정보 http://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions

여기에서 많은 방법을 시도했지만 복잡하거나 내 요구 사항을 충족하지 못했습니다. 실제로, 도우미 방법을 아주 간단하게 쓸 수 있습니다.

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

제로 의존성 : mockito가 필요하지 않으며, PowerMock이 필요하지 않습니다. 그리고 최종 수업에서 잘 작동합니다.

내가 찾은 Junit 4의 가장 유연하고 우아한 답변은 Mkyong 블로그. 그것은 유연성이 있습니다 try/catch 사용 @Rule 주석. 사용자 정의 된 예외의 특정 속성을 읽을 수 있기 때문에이 접근법이 마음에 듭니다.

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

    }

}

Java 8 솔루션

다음과 같은 솔루션을 원하시면 다음과 같습니다.

  • Java 8 Lambdas를 사용합니다
  • 하다 ~ 아니다 Junit Magic에 의존합니다
  • 단일 테스트 방법 내에서 여러 예외를 확인할 수 있습니다.
  • 전체 테스트 방법에서 알려지지 않은 라인 대신 테스트 방법 내의 특정 라인 세트에 의해 예외가 발생하는지 확인합니다.
  • 더 자세히 살펴볼 수 있도록 버린 실제 예외 객체를 생성합니다.

다음은 내가 쓴 유틸리티 기능입니다.

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은 이에 대한 내장 지원을 받았습니다 "예상"속성

제 경우에는 항상 DB에서 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));
}

다음과 같이 켜지거나 켜질 수있는 매치 자만 만듭니다.

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

그것을 사용하려면 :

추가하다 public ExpectedException exception = ExpectedException.none();, 그 다음에:

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

Junit 4 이상에서는 다음과 같이 예외를 테스트 할 수 있습니다.

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


이것은 주니트 테스트를 개선하는 데 사용할 수있는 많은 기능을 제공합니다.
아래 예제가 표시되면 예외에서 3 가지를 테스트하고 있습니다.

  1. 예외의 유형
  2. 예외 메시지
  3. 예외의 원인


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

}

예외를 반환 해야하는 메소드 후에 어설 션 실패를 사용할 수 있습니다.

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

무엇에 추가 Namshubwriter 다음과 같이 말했습니다.

  • expectionException 인스턴스입니다 공공의 (관련 질문)
  • 예상 예상 그렇지 않습니다 @before 방법에 인스턴스화됩니다. 이것 게시하다 Junit의 실행 순서의 모든 복잡성을 명확하게 설명합니다.

하다 ~ 아니다 이 작업을 수행:

@Rule    
public ExpectedException expectedException;

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

드디어, 이것 블로그 게시물은 특정 예외가 발생한다고 주장하는 방법을 명확하게 보여줍니다.

나는 도서관을 추천한다 assertj-core 주니트 테스트에서 예외를 처리합니다

Java 8에서는 다음과 같습니다.

//given

//when
Throwable throwable = catchThrowable(() -> anyService.anyMethod(object));

//then
AnyException anyException = (AnyException) throwable;
assertThat(anyException.getMessage()).isEqualTo("........");
assertThat(exception.getCode()).isEqualTo(".......);

Java8을 사용한 Junit4 솔루션은이 기능을 사용하는 것입니다.

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

사용법은 다음과 같습니다.

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

유일한 제한은 a를 사용하는 것입니다 final 람다 표현식에서 객체 참조. 이 솔루션은 방법을 사용하여 방법 수준에서 thowable을 기대하는 대신 테스트 어설 션을 계속할 수 있습니다. @Test(expected = IndexOutOfBoundsException.class) 해결책.

예를 들어, 아래 언급 된 코드 조각에 대해 Junit을 쓰고 싶습니다.

public int divideByZeroDemo(int a,int b){

    return a/b;
}

public void exceptionWithMessage(String [] arr){

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

위의 코드는 발생할 수있는 알려지지 않은 예외를 테스트하는 것이며 아래는 사용자 정의 메시지로 예외를 주장하는 것입니다.

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

Java 8을 사용하면 매개 변수로 확인하고 예상 예외를 확인하기 위해 코드를 취하는 메소드를 만들 수 있습니다.

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

그리고 테스트 안에서 :

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

이익:

  • 도서관에 의존하지 않습니다
  • 현지화 된 점검 - 필요한 경우 한 번의 테스트 내에서 이와 같은 여러 가지 주장을 할 수 있습니다.
  • 사용하기 쉬운

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

기능적 인 인터페이스를 정의해야합니다 Runnable 필요한 것을 선언하지 않습니다 throws.

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

이 방법은 다음과 같이 사용할 수 있습니다.

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

테스트 케이스를 작성하는 두 가지 방법이 있습니다

  1. 방법에 의해 던져지는 예외로 테스트에 주석을 달다. 이 같은 @Test(expected = IndexOutOfBoundsException.class)
  2. Try Catch Block을 사용하여 테스트 클래스에서 예외를 포착하고 테스트 클래스의 메소드에서 던져진 메시지를 주장 할 수 있습니다.

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

나는 이것이 당신의 쿼리 행복한 학습에 답하기를 바랍니다 ...

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top