2013-07-18 19 views
7

Masz pytanie dotyczące wykorzystania ExpectedException reguły JUnit za:Jak mogę przetestować kilka wyjątków w ramach jednego testu przy użyciu reguły ExpectedException?

Jak sugeruje tutaj: junit ExpectedException Rule począwszy od JUnit 4.7 można przetestować wyjątki takie jak to (co jest dużo lepiej niż w @Test (oczekiwane = Exception.class)) :

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

@Test 
public void testFailuresOfClass() { 
Foo foo = new Foo(); 
exception.expect(Exception.class); 
foo.doStuff(); 
} 

Teraz musiałem przetestować kilka wyjątków w jednej metodzie testu i otrzymałem zielony pasek po wykonaniu poniższego testu i dlatego uważałem, że każdy test minął.

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

exception.expect(IndexOutOfBoundsException.class); 
foo.doStuff(); 

//this is not tested anymore and if the first passes everything looks fine 
exception.expect(NullPointerException.class); 
foo.doStuff(null); 

exception.expect(MyOwnException.class); 
foo.doStuff(null,""); 

exception.expect(DomainException.class); 
foo.doOtherStuff(); 
} 

Po chwili jednak zdałem sobie sprawę, że test testowy kończy się po pierwszym sprawdzeniu. Jest to co najmniej dwuznaczne. W JUnit 3 to było możliwe łatwe ... Więc tutaj jest moje pytanie:

Jak mogę przetestować kilka wyjątków w ciągu jednego badania z użyciem ExpectedException regułę?

+0

Nadal można używać metody Junit 3, ale nie jest to możliwe przy użyciu @Test (oczekiwane) ani ExpectedException. –

+0

Tak się bałem ;-) – Lonzak

+1

To nie jest takie złe. Zwykle lepiej przetestować jedną rzecz na każdy test. Jest w porządku, jeśli testujesz, na przykład notNull, rozmiar i zawartość listy w tym samym teście, ale nie testuj dwóch konceptualnych różnych rzeczy w jednym teście. Jest mniej czytelny. Jeśli testujesz jedną rzecz na test, możesz użyć nazwy metody, aby opisać to, co testujesz, zamiast "testException" –

Odpowiedz

6

Krótka odpowiedź: Nie możesz.

Jeśli pierwsze połączenie - z foo.doStuff() - zgłasza wyjątek, nigdy nie dotrzesz do foo.doStuff(null). Musisz podzielić na kilka testów (i dla tej banalnej sprawy bym zaproponować powrót do prostego zapisu, bez ExpectedException):

private Foo foo; 

@Before 
public void setUp() { 
foo = new Foo(); 
} 

@Test(expected = IndexOutOfBoundsException.class) 
public void noArgsShouldFail() { 
foo.doStuff(); 
} 

@Test(expected = NullPointerException.class) 
public void nullArgShouldFail() { 
foo.doStuff(null); 
} 

@Test(expected = MyOwnException.class) 
public void nullAndEmptyStringShouldFail() { 
foo.doStuff(null,""); 
} 

@Test(expected = DomainException.class) 
public void doOtherStuffShouldFail() { 
foo.doOtherStuff(); 
} 

Jeśli naprawdę chcesz jeden i tylko jeden test, można fail jeśli nie zostanie zgłoszony błąd i złapać rzeczy można oczekiwać:

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

try { 
    foo.doStuff(); 
    fail("doStuff() should not have succeeded"); 
} catch (IndexOutOfBoundsException expected) { 
    // This is what we want. 
} 
try { 
    foo.doStuff(null); 
    fail("doStuff(null) should not have succeeded"); 
} catch (NullPointerException expected) { 
    // This is what we want. 
} 
// etc for other failure modes 
} 

robi to dość niechlujny dość szybko, choć i jeśli pierwszy oczekiwanie zakończy się niepowodzeniem, nie będzie widać, czy coś jeszcze nie tak dobrze, co może być denerwujące podczas rozwiązywania problemów.