2013-08-01 28 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

たuncaughtExceptionHandlerがキャッチされない例外を取得doesntのように、テスト中にスローされるすべての例外は、JUnitのでキャッチされ処理されているためです。これは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はテストメソッドをtry catchブロックでラッピングしているので、例外は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

これは奇妙なテストです。テストしたい '実際の'コードは、スレッドUncaughtExceptionHandlerを使用しています。だから、junitがこのように動作するので、私はそのコードをjunitでテストすることはできません。上記のテストは問題を示すことに過ぎず、私はJVM仕様をテストしようとしていません。 –

+0

@Rob 'MyUncaughtExceptionHandler'をテストするために' MyUncaughtExceptionHandlerTest'を作成し、テストから 'uncaughtException'を呼び出してください。 'java.lang.Thread'クラスのインスタンスをテストすることを忘れて、それらのインスタンスを作成してください。 – kan

+0

Hmmm、技術的には、testMethod()はNPEやMyUncaughtExceptionHandlerによって捕まえられる例外を投げてはなりません。何とかJUNITがその動作を無効にしていて、例外がスローされます。最終的に私の質問はHOWに変身し、JUNITはスレッドUncaughtExceptionHandlerを無効にします。 –

関連する問題