2012-11-05 16 views
49

Testuję metodę z oczekiwanym wyjątkiem. Muszę również sprawdzić, czy po wywołaniu wyjątku został wywołany kod czyszczenia (na wyśmiewanym obiekcie), ale wygląda na to, że weryfikacja jest ignorowana. Oto kod. Korzystam z Junit ExpectedExceptionRule, aby zweryfikować oczekiwany wyjątek.Mockito sprawdź po wyjątku Junit 4.10

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

@Test 
public void testExpectedException() 
{ 
    MockedObject mockObj = mock(MockedObj.class); 
    MySubject subject = new MySubject(mockedObj); 
    expectedEx.expect(MyException.class); 
    expectedEx.expectMessage("My exception message."); 
    subject.someMethodThrowingException(); 
    verify(mockObj). 
     someCleanup(eq(...)); 
} 

Wydaje się, że verify jest całkowicie ignorowany. Bez względu na to, jaką metodę wstawiłem do verify, mój test mija, co nie jest tym, czego chcę.

Każdy pomysł, dlaczego tak się dzieje?

Odpowiedz

51

ExpectedException działa przez wrapping your entire test method w bloku try-catch za pośrednictwem JUnit @Rule. Kiedy twój kod zgłasza wyjątek, przechodzi na stos do najbliższego try/catch, który znajduje się w instancji ExpectedException (która sprawdza, czy jest to wyjątek, którego się spodziewasz).

W języku Java, jeśli wystąpi nieprzechwycony wyjątek w metodzie, kontrola nigdy nie powróci do instrukcji później w tej metodzie. Obowiązują tu te same zasady: Kontrola nigdy nie wraca do instrukcji w teście po wystąpieniu wyjątku.

Technicznie, możesz umieścić weryfikacje w ostatecznym bloku, ale to zwykle jest a bad habit. W każdym razie prawdopodobnie połknie użyteczną wiadomość o numerze ExpectedException, ponieważ będzie działała zanim reguła ExpectedException może ją przechwycić.

Jeśli naprawdę potrzebujesz, aby sprawdzić stan po wyjątku, na podstawie za metody, zawsze możesz wrócić do tego idiomu:

@Test 
public void testExpectedException() 
{ 
    MockedObject mockObj = mock(MockedObj.class); 
    MySubject subject = new MySubject(mockedObj); 
    try { 
    subject.someMethodThrowingException(); 
    fail("Expected MyException."); 
    } catch (MyException expected) { 
    assertEquals("My exception message.", expected.getMessage()); 
    } 
    verify(mockObj).someCleanup(eq(...)); 
} 

Aktualizacja: z Java 8 w wyrażeniach lambda, można zawiń funkcjonalne wywołanie interfejsu w bloku próbnym concisely enough to be useful. Wyobrażam sobie, że wsparcie dla tej składni trafi do wielu standardowych bibliotek testowych.

assertThrows(MyException.class, 
    () -> systemUnderTest.throwingMethod()); 
4

nie próbowałem tego jeszcze, ale oprócz doskonałej odpowiedź Jeff Bowmana, może masz wybór korzystania z ExpectedException Regułę z try ... finally skonstruować, umieszczając zweryfikować oświadczenie w końcu blok.

+0

Sprawdź mój punkt środkowy ... Myślę, że będzie działać, ale byłoby przełknąć wiadomość ExpectedException. Dzięki za komplement! –

+0

Nieodebrane - prawdopodobnie prawo. –

+3

Wreszcie działa dobrze dla mnie - wykonuje weryfikację i wciąż wykrywa oczekiwany wyjątek, a jego komunikat –

6

bardziej eleganckie rozwiązanie z catch-exception

@Test 
public void testExpectedException() 
{ 
    MockedObject mockObj = mock(MockedObject.class); 
    MySubject subject = new MySubject(mockObj); 

    when(subject).someMethodThrowingException(); 

    then(caughtException()) 
      .isInstanceOf(MyException.class) 
      .hasMessage("My exception message."); 

    verify(mockObj).someCleanup(eq(...)); 
}