2013-08-01 1 views
6

В приведенном ниже примере кода, если testMethod() запущен через main(), он работает так, как ожидалось, но если он запущен через JUNIT, то MyUncaughtExceptionHandler не будет вызван.Java Thread.currentThread(). SetUncaughtExceptionHandler() не работает с JUNIT?

Есть ли какое-то объяснение для этого?

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

Что странно способ вызвать NPE, почему не просто 'певд NullPointerException()'? – kan

+0

throw new NullPointerException() сделает байт-код в testMethod() немного другим. Настоящий код, который я искал для тестирования, использует усовершенствование байт-кода, и это имеет значение в этом случае. Если бы у меня это получилось, как ожидалось в junit, я бы затем улучшил testMethod(). –

+0

дайте более подробную информацию, я думаю, мы могли бы найти лучший подход. Возможно, вам нужно создать новый поток, загрузчик классов или даже экземпляр JVM в тесте, но это будет интеграционный тест, а не единичный тест. – kan

ответ

5

Это потому, что все исключения, которые выбрасываются в тесте перехватываются и обрабатываются JUnit, так UncaughtExceptionHandler не получает каких-либо пойманные исключения. Это делается в 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

Да - это правильный ответ. JUNIT обертывает тестовый метод блоком catch try, поэтому исключение никогда не рассматривается как UncaughtException (это не тот случай, когда выполняется через метод main()). Теперь очевидно. Благодарю. –

7

Очевидно, что обработчик setUncaughtExceptionHandler наборов для неперехваченных исключений. Но JUnit ловит все исключения, полученные из тестовых методов.

В любом случае, это странный способ сделать единичный тест. Ед. Тест должен проверять ваш код, а не спецификацию JVM.

Я представляю юнит тест так:

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

Это нечетный тест - «реальный» код, который я хочу протестировать, использует Thread UncaughtExceptionHandler. Так как junit действует таким образом, я не могу проверить этот код (с junit). Тест выше - это просто показать проблему, я не пытаюсь проверить спецификацию JVM. –

+0

@Rob Вы должны сделать 'MyUncaughtExceptionHandlerTest', чтобы проверить' MyUncaughtExceptionHandler', вызывать 'uncaughtException' из теста. И забудьте о тестировании экземпляров класса 'java.lang.Thread', создайте для них mocks. – kan

+0

Хммм, технически testMethod() не должен бросать NPE или какое-либо исключение, так как он будет заражен MyUncaughtExceptionHandler. Как-то JUNIT отключает это поведение и генерирует исключение. В конечном счете мой вопрос превращается в HOW и ПОЧЕМУ JUNIT отключает Thread UncaughtExceptionHandler. –

Смежные вопросы