2013-08-01 14 views
6

W poniższym przykładowym kodzie, jeśli metoda testMethod() jest uruchamiana przez funkcję main(), działa ona zgodnie z oczekiwaniami, ale jeśli jest uruchamiana przez JUNIT, wówczas wywołanie MyUncaughtExceptionHandler nie jest wywoływane.Java Thread.currentThread(). SetUncaughtExceptionHandler() nie działa z JUNIT?

Czy jest jakieś wyjaśnienie tego?

package nz.co.test; 

import java.lang.Thread.UncaughtExceptionHandler; 

import org.junit.Test; 

public class ThreadDemo { 

    private void testMethod() { 
    Thread.currentThread().setUncaughtExceptionHandler(new MyUncaughtExceptionHandler()); 

    Object b = null; 
    // Cause a NPE 
    b.hashCode(); 
    } 

    @Test 
    public void testJunit() { 
    // Run via JUnit and MyUncaughtExceptionHandler doesn't catch the Exception 
    testMethod(); 
    } 

    public static void main(String[] args) { 
    // Run via main() works as expected 
    new ThreadDemo().testMethod(); 
    } 

    static class MyUncaughtExceptionHandler implements UncaughtExceptionHandler { 

    @Override 
    public void uncaughtException(Thread t, Throwable e) { 
     System.out.println("I caught the exception"); 
    } 
    } 
} 
+0

Co to jest dziwny sposób na NPE, dlaczego nie po prostu "rzucić nowe NullPointerException()'? – kan

+0

throw new NullPointerException() sprawiłoby, że bajt kodujący w trybie testMethod() byłby nieco inny. Prawdziwy kod, który próbowałem przetestować, wykorzystuje rozszerzenie kodu bajtowego i robi różnicę w tym przypadku. Jeśli mam to działać zgodnie z oczekiwaniami, to poprawię metodę testMethod(). –

+0

podać więcej szczegółów, myślę, że możemy znaleźć lepsze podejście. Być może w teście musisz odradzić nowy wątek, klasę ładującą lub nawet instancję JVM, ale będzie to test integracyjny, a nie test jednostkowy. – kan

Odpowiedz

5

To dlatego, że wszystko Wyjątkiem są wyrzucane w teście zostały złowione i przetwarzane przez JUnit, więc nie robi się żadnych UncaughtExceptionHandler niezłapane wyjątki. Robi się to w org.junit.runners.ParentRunners

... 
    protected final void runLeaf(Statement statement, Description description, 
      RunNotifier notifier) { 
     EachTestNotifier eachNotifier = new EachTestNotifier(notifier, description); 
     eachNotifier.fireTestStarted(); 
     try { 
      statement.evaluate(); <-- test method execution is called from here 
     } catch (AssumptionViolatedException e) { 
      eachNotifier.addFailedAssumption(e); 
     } catch (Throwable e) { 
      eachNotifier.addFailure(e); 
     } finally { 
      eachNotifier.fireTestFinished(); 
     } 
    } 
+1

Tak - to jest poprawna odpowiedź. JUNIT polega na zawijaniu metody testowej za pomocą bloku catch catch, więc wyjątek nigdy nie jest traktowany jako wyjątek UncaughtException (co nie ma miejsca w przypadku uruchamiania za pomocą metody main()). Niby oczywiste teraz. Dzięki. –

7

Oczywiście, zestawy do obsługi setUncaughtExceptionHandler Uncaught wyjątkami. Ale JUnit przechwytuje wszystkie wyjątki wyrzucane z metod testowych.

W każdym razie to dziwny sposób na sprawdzenie urządzenia. Test jednostkowy powinien przetestować twój kod, a nie specyfikację JVM.

Wyobrażam sobie test jednostka tak:

public class MyUncaughtExceptionHandlerTest 
{ 
    @Mock Thread thread; 
    MyUncaughtExceptionHandler testObject = new MyUncaughtExceptionHandler(); 

    @Before 
    public void setUp() 
    { 
    MockitoAnnotations.initMocks(this); 
    } 

    @Test 
    public void handleNpeShouldDoOneThing() 
    { 
    testObject.handleException(thread, new NullPointerException()); 
    //verify(oneThing) 
    } 

    @Test 
    public void handleOomShouldDoSomethingElse() 
    { 
    testObject.handleException(thread, new OutOfMemoryError()); 
    //verify(somethingElse) 
    } 
} 
+0

To jest dziwny test - "prawdziwy" kod, który chcę przetestować, wykorzystuje wątek UncaughtExceptionHandler. Więc ponieważ junit działa w ten sposób, nie mogę przetestować tego kodu (z połączeniem). Powyższy test jest tylko po to, aby pokazać problem, nie próbuję testować specyfikacji JVM. –

+0

@Rob Powinieneś wykonać 'MyUncaughtExceptionHandlerTest', aby przetestować' MyUncaughtExceptionHandler', wywołaj 'uncaughtException' z testu. I zapomnij o testowaniu instancji klasy 'java.lang.Thread', twórz dla nich makiety. – kan

+0

Hmmm, technicznie testMethod() nie powinien wyrzucać NPE ani żadnego wyjątku, ponieważ zostanie przechwycony przez MyUncaughtExceptionHandler. W jakiś sposób JUNIT wyłącza to zachowanie, a wyjątek zostaje zgłoszony. Ostatecznie moje pytanie zmienia się na JAK i DLACZEGO JUNIT wyłącza wątek UncaughtExceptionHandler. –

Powiązane problemy