2013-08-01 14 views
6

Nel codice di esempio seguente, se il testMethod() viene eseguito tramite main() funziona come previsto ma se viene eseguito tramite JUNIT, MyUncaughtExceptionHandler non viene richiamato.Java Thread.currentThread(). SetUncaughtExceptionHandler() non funziona con JUNIT?

C'è qualche spiegazione per questo?

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

Che cosa è un modo strano per causare NPE, perché non solo 'throw new NullPointerException()'? – kan

+0

lanciare il nuovo NullPointerException() renderebbe il bytecode in testMethod() un po 'diverso. Il codice reale che stavo cercando per testare utilizza l'ottimizzazione bytecode e fa la differenza in quel caso. Se riuscissi a far funzionare tutto come previsto in junit, avrei quindi migliorato testMethod(). –

+0

fornire maggiori dettagli, penso che potremmo trovare un approccio migliore. Forse hai bisogno di generare una nuova discussione, un classloader o anche un'istanza di JVM nel test, ma sarà un test di integrazione, non un test di unità. – kan

risposta

5

Questo perché tutte eccezione che vengono gettati in un test vengono catturati ed elaborati da JUnit, così UncaughtExceptionHandler non ottiene tutte le eccezioni non gestite fanno. E 'fatto in 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

Sì, questa è la risposta corretta. JUNIT esegue il wrapping del metodo di prova con il blocco catch try in modo che l'eccezione non venga mai considerata come UncaughtException (che non è il caso quando viene eseguita tramite il metodo main()). Un po 'ovvio ora. Grazie. –

7

Ovviamente, il gestore setUncaughtExceptionHandler set per le eccezioni non gestite fanno. Ma JUnit recupera tutte le eccezioni generate dai metodi di prova.

In ogni caso, è un modo strano di fare un test unitario. Il test unitario dovrebbe testare il codice, non la specifica JVM.

immagino uno unit test come questo:

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

È un test dispari: il codice "reale" che voglio testare utilizza Thread UncaughtExceptionHandler. Quindi, poiché junit agisce in questo modo, non posso testare quel codice (con junit). Il test di cui sopra è solo per mostrare il problema, non sto provando a testare le specifiche JVM. –

+0

@Rob Si dovrebbe fare un 'MyUncaughtExceptionHandlerTest' per testare' MyUncaughtExceptionHandler', chiamare 'uncaughtException' dal test. E dimentica di testare le istanze di classe 'java.lang.Thread', creare mock per loro. – kan

+0

Hmmm, tecnicamente il testMethod() non dovrebbe generare NPE o alcuna eccezione in quanto verrà catturato da MyUncaughtExceptionHandler. In qualche modo, JUNIT sta disabilitando quel comportamento e l'eccezione viene generata. Alla fine la mia domanda si trasforma in COME e PERCHE 'JUNIT disabilita il Thread UncaughtExceptionHandler. –

Problemi correlati