2017-06-19 5 views
5

私はいくつかのコードを非同期に変換しています。元の単体テストでは注釈@Test(expected = MyExcpetion.class)を使用しましたが、私がアサートしたい例外はjava.util.concurrent.ExcutionExceptionにラップされているため、これは機能しないと思います。私はこのように自分の将来を呼び出してみましたが、私の主張は、まだ失敗していると私は、私もこの味を試してみましたreturn null将来どのように例外をテストできますか?

myApiCall.get(123).exceptionally((ex) -> { 
assertEquals(ex.getCause(),MyCustomException.class) 
return null 
} 

に追加する必要がありましたことを愛していないが、まだ働いていない

myApiCall.get(123).exceptionally((ex) -> { 
assertThat(ex.getCause()) 
    .isInstanceOF(MyException.class) 
    .hasMessage("expected message etc") 
return null; 
} 

IDを見つけることができない場合、私のAPIは単に例外をスローします。これを適切にテストするにはどうすればよいですか?とにかく元の注釈を使用できますか?

実行時に私のapiコールがdbに届きます。このテストでは、エラーを返すように未来を設定しているので、実際に何かと通信しようとはしません。テスト対象のコードが、私は例外をテストし、また、ユニットテスト、これを維持することができるように不正なデータを返すためにmyService.getFromDB(id)を強制するユニットテストでこの

public class myApiCall { 
    public completableFuture get(final String id){ 
    return myService.getFromDB(id) 
    .thenApply( 
     //code here looks at result and if happy path then returns it after 
     //doing some transformation 
     //otherwise it throws exception 
    ) 
    } 
} 

のように見えるデシベルなどに

+0

おそらく、あなたの 'get'は別のスレッドに委譲します。 JUnitは完了を待たないことに注意してください。テストメソッドを終了すると、Javaプロセスが終了します。代わりに、結果を待つためにCFで 'get'を実行します。例外がある場合は、それをアンラップしてそこにアサートしてください(あるいはそれをやり直して、あなたの 'expected'を使用してください)。 –

+0

ここにmyApiCallとは何ですか? – fxrbfg

+0

apiコールはデータのためにdbに届きます。上記のコードで何かを更新しましょう。 – Barry

答えて

4

に手を差し伸べるしていませんさんは0で呼び出された場合、あなたのAPIが投げると仮定しましょう:

public static CompletableFuture<Integer> apiCall(int id) { 
    return CompletableFuture.supplyAsync(() -> { 
    if (id == 0) throw new RuntimeException("Please not 0!!"); 
    else return id; 
    }); 
} 

次のコードで期待どおりに動作することをテストすることができます(私はTestNGのを使用していますが、私はJUnitのに変換するにはあまりにも難しいことではないだろう疑いますテスト):

@Test public void test_ok() throws Exception { 
    CompletableFuture<Integer> result = apiCall(1); 
    assertEquals(result.get(), (Integer) 1); 
} 

@Test(expectedExceptions = ExecutionException.class, 
     expectedExceptionsMessageRegExp = ".*RuntimeException.*Please not 0!!") 
public void test_ex() throws Throwable { 
    CompletableFuture<Integer> result = apiCall(0); 
    result.get(); 
} 

この2番目のテストでは、ExecutionExceptionメッセージに元の例外の種類とメッセージが含まれており、正規表現で期待値を取得していることに注意してください。 JUnitでそれを行うことができない場合は、try/catchブロックでresult.get()に電話をかけ、catchブロックでthrow e.getCause();と呼ぶことができます。言い換えれば、このようなもので:

@Test(expectedExceptions = RuntimeException.class, 
     expectedExceptionsMessageRegExp = "Please not 0!!") 
public void test_ex() throws Throwable { 
    CompletableFuture<Integer> result = apiCall(0); 
    try { 
    result.get(); 
    } catch (ExecutionException e) { 
    throw e.getCause(); 
    } 
} 
+0

私はJUnitフレーバーに問題があったので、上記のテストのスタイルで '.get'を試しにキャッチして例外の原因を主張して動作させました。 '@Test(expected = MyException.class)を試したときに問題が発生しましたが、例外が発生した場合は例外を再現するかどうか疑問に思っていますが、エラーで深いアサーションを実行したかったのでtry/catchでOKでした。 – Barry

0

また、代替オプションを試すことができます。

import org.hamcrest.core.IsInstanceOf; 
import org.junit.rules.ExpectedException; 

public class Test() { 

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

    @Test 
    public void myApiCallTest() { 
     thrown.expect(ExcutionException.class); 
     thrown.expectCause(IsInstanceOf.instanceOf(MyException.class)); 
     thrown.expectMessage("the message you expected"); 
     myApiCall.get(""); 
    } 
} 

と仮定すると:JUnitの-4でやって簡単なことである

public class myApiCall { 
    public completableFuture get(final String id) { 
     // ... 
     throw new ExcutionException(new MyException("the message you expected")) 
    } 
} 
1

@RunWith注釈を覚えていますか?はい、JUnitの期待例外プロセッサが呼び出される前に、例えば、例外をインターセプトするTestRunnerあなた自身を記述します。

public class ConcurrentRunner extends BlockJUnit4ClassRunner { 

    public ConcurrentRunner(Class<?> klass) throws InitializationError { 
     super(klass); 
    } 


    @Override 
    protected Statement possiblyExpectingExceptions(FrameworkMethod method, 
                Object test, 
                Statement next) { 
     return super.possiblyExpectingExceptions(
       method, test, throwingActualException(next) 
     ); 
    } 

    private Statement throwingActualException(Statement next) { 
     return new Statement() { 
      @Override 
      public void evaluate() throws Throwable { 
       try { 
        next.evaluate(); 
       } catch (ExecutionException | CompletionException source) { 
        throw theActualExceptionOf(source); 
       } 
      } 

      private Throwable theActualExceptionOf(Exception source) { 
       return source.getCause() != null ? source.getCause() : source; 
      } 
     }; 
    } 
} 

は単なるテストの@RunWith(ConcurrentRunner.class)で注釈を付け、あなたは、すべてのテストコードを変更する必要はありません。

@RunWith(ConcurrentRunner.class) 
public class ConcurrentExpectedExceptionTest { 

    @Test(expected = IllegalArgumentException.class) 
    public void caughtTheActualException() throws Throwable { 
     myApiCall().join(); 
    } 

    private CompletableFuture<Object> myApiCall() { 
     return CompletableFuture.supplyAsync(() -> { 
      throw new IllegalArgumentException(); 
     }); 
    } 
} 
関連する問題