2016-03-06 36 views
9

Ustawiłem test JUnit (4.12) z funkcją ExpectedException i chciałbym, aby test był kontynuowany po oczekiwanym wyjątku. Ale nigdy nie widzę logu "3", ponieważ wykonanie wydaje się zatrzymywać po wyjściu, zdarzenie w przypadku złapania?Jak kontynuować test po wyrzuceniu JUnit ExpectedException?

Czy jest to rzeczywiście możliwe i jak?

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

@Test 
public void testUserAlreadyExists() throws Exception { 
    log.info("1"); 

    // Create some users 
    userService.createUser("toto1"); 
    userService.createUser("toto2"); 
    userService.createUser("toto3"); 
    Assert.assertTrue(userService.userExists("toto1")); 
    Assert.assertTrue(userService.userExists("toto2")); 
    Assert.assertTrue(userService.userExists("toto3")); 

    log.info("2"); 

    // Try to create an existing user 
    exception.expect(AlreadyExistsException.class); 
    userService.createUser("toto1"); 

    log.info("3"); 
} 
+0

możesz chcieć zrewidować pisanie takiego testu, w którym chcesz wykonać coś po zgłoszeniu wyjątku. Jeśli jest coś, co chcesz przetestować, powinieneś podzielić je na dwa różne testy: jeden, który sprawdza wyjątek, a drugi sprawdza drugą logikę. –

+1

Możliwy duplikat [JUnit kontynuuje potwierdzanie rzeczy po oczekiwanym wyjątku] (http://stackoverflow.com/questions/21506079/junit-continue-to-assert-things-after-expected-exception) – Joe

Odpowiedz

5

nie można zrobić, gdy jest wyjątek to rzucony na prawdziwe, ExpectedException reguły czy nie.

Jeśli naprawdę chcesz tego rodzaju zachowania, można wrócić do „starej szkoły” wzoru:

try { 
    userService.createUser("toto1"); 
    Assert.fail("expecting some AlreadyExistsException here") 
} catch (AlreadyExistsException e) { 
    // ignore 
} 

log.info("3"); 

Ale nie przeszkadza jakiegoś dziennika.

+0

OK, potwierdzasz, co ja myślał, nie ma możliwości z tym. Może mój approch nie jest najlepszy, tak jak opisuje to @packer. – Deathtiny

2

Ten SO rozwiązaniem wydaje się robić to, co chcesz zrobić: JUnit continue to assert things after expected exception

ja myślałem coś podobnego. Aby kontynuować test, w teście musiałbyś złapać wyjątek. To rozwiązanie pokazuje elegancki sposób robienia tego.

Uwaga: Jeśli reguła oczekuje wyjątku (tak jak to się stało), test zakończy się powodzeniem, gdy tylko zostanie zgłoszony wyjątek. Dotyczy: http://junit.org/javadoc/latest/org/junit/rules/ExpectedException.html

1

Przede wszystkim Twój test nie testuje jednej rzeczy. Testuje "userExists" i "createUser" w różnych warunkach a.k.a. różnych scenariuszach. Nazywa się to AssertionRoulette. Nie potrzebujesz hackowania, aby kontynuować rejestrowanie "3", jeśli napiszesz testy, które zawiodą z właściwego powodu.

Jeśli testy zakończą się niepowodzeniem z właściwego powodu, można zobaczyć scenariusz, dlaczego się nie powiedzie, bez wykonywania wszystkich czynności związanych z rejestrowaniem. Junit-Runner już robi rejestrację.

@Test 
public void testUserExists_UserCreatedUserNotExistent_expectTrue() 
{ 
    // Create some users 
    userService.createUser("toto1"); 

    // Assert That user exists 
    Assert.assertTrue(userService.userExists("toto1")); 
} 

@Test 
public void testCreateUser_UserAlreadyCreated_expectAlreadyExistsExceptionIsThrown() 
{ 
    // Create some users 
    userService.createUser("toto1"); 

    // Try to create an existing user 
    exception.expect(AlreadyExistsException.class); 
    userService.createUser("toto1");  
} 
+0

Jako że userService używa MongoDB, problem z tym podejściem polega na tym, że jedna metoda testowa już inicjuje dane (createUser), a drugi test kończy się niepowodzeniem. Czy powinienem wyczyścić DB po każdej metodzie testu? – Deathtiny

+0

Można utworzyć regułę, która tworzy jednorazowość dla każdego testu i zbuduje małą usługę, która utworzy unikalną nazwę. Zamiast "toto1" będzie to "YzFAE4qd_toto1".Po prostu będziesz mieć różnych użytkowników dla każdego testu. Niedawno widziałem to podejście - ale nie pamiętam, gdzie. Dodam to do mojej odpowiedzi, jeśli znajdę odniesienie ponownie. – thepacker

+0

Możesz wyczyścić db po zakończeniu zajęć. @ BeforeClass i @ AfterClass, jeśli potrzebujesz, ale Reguła może również oczyścić użytkowników. Jest zbyt wiele możliwości. – thepacker

1

Jeśli nie chcesz dodawać wiele podobnych metod badawczych na coś, co ma wiele opcji, aby rzucić oczekiwany wyjątek i chcesz sprawdzić, czy to rzeczywiście rzuca na wszystkich pożądanych spraw w pojedyncza jednostka test zamiast, polecam ten (nie całkiem może) jako schematu:

@Test 
public void testThatSomethingExpectedlyFails() { 
    for (int i = 1; i <= 3; i++) { 
     try { 
      switch (i) { 
       case 1: // smth here throws the exception when configuration #1; 
       case 2: // smth here throws the exception when configuration #2; 
       case 3: // smth here throws the exception when configuration #3; 
      } 
     } catch (ExceptionThatIsExpected expected) { 
      continue; 
     } catch (Exception unexpected) { 
      /* the test must fail when an unexpected exception is thrown */     
      fail("The test has failed due to an unexpected exception: " + unexpected.getMessage()); // or just re-throw this exception 
     } 

     /* the test must fail when a case completes without the expected exception */ 
     fail("No expected exception occurred at case " + i); 
    } 
} 

jeden może również iteracyjne przedmiotów (a nawet wykonywać funkcje) jakiegoś wstępnie przygotowanej liście zamiast przełącznika-w przypadku ciężko zakodowane liczby całkowite.