2012-10-22 11 views
5

データベースにたくさんのjava.sql.Connectionを使用するJavaアプリケーションがあります。テスト用に確定的にDBを失敗させる

データベースが利用できない場合、私のサービスは適切なエラーコード(HTTP 500と503などの一時的な問題と永続的な問題を区別する)を返します。

私のアプリケーションは、組み込みのローカルメモリ内のh2データベースに接続します。アプリケーションがこれを認識していない、私の統合テストのみです。

データベースへの書き込みを決定的に失敗させる方法を教えてください。コミットしてカスタムをスローするようにしますSQLException?私は、すべての接続に影響を与え、私のアプリケーションが再接続ロジックを実行するように、グローバルな「データベースが利用できません」ブール値をテストコードに入れたいと思います。

(私はConnectionをプロキシとcommit()if(failFlag) throw new MySimulateFailureException()を置くことによって始めていた。しかし、これはPreparedStatement.executeUpdate()をキャッチしていませんでした。私はあまりにもPreparedStatementをプロキシに着手する前に - 方法のその多くを - 私が教えられるしたいと思います!良い方法...)

+2

これは愚かに聞こえるが、なぜデータベースサービスを停止しない場合がありますか?ファイアウォールのポートをブロックしてトラフィックを少し拒否することはできますか? – Serdalis

+2

私は通常上記で概説したプロキシルートに行きます。誰かがより良いアプローチをしているなら、それを聞くことに興味があるでしょう。 – Keppil

答えて

0

は、私は自分のJavaリフレクションConnection.commitをインターセプトラッパーとPreparedStatement.execute...メソッドを作ることになりました。私の「DBFactory」クラスの

私の最終的なコード:

@SuppressWarnings("serial") 
public class MockFailureException extends SQLException { 
    private MockFailureException() { 
     super("The database has been deliberately faulted as part of a test-case"); 
    } 
} 

private class MockFailureWrapper implements InvocationHandler { 

    final Object obj; 

    private MockFailureWrapper(Object obj) { 
     this.obj = obj; 
    } 

    @Override public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { 
     if(dbFailure && ("commit".equals(m.getName()) || m.getName().startsWith("execute"))) 
      throw new MockFailureException(); 
     Object result; 
     try { 
      result = m.invoke(obj, args); 
      if(result instanceof PreparedStatement) 
       result = java.lang.reflect.Proxy.newProxyInstance(
         result.getClass().getClassLoader(), 
         result.getClass().getInterfaces(), 
         new MockFailureWrapper(result)); 
     } catch (InvocationTargetException e) { 
      throw e.getTargetException(); 
     } catch (Exception e) { 
      throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); 
     } 
     return result; 
    } 

} 


public Connection newConnection() throws SQLException { 
    Connection connection = DriverManager.getConnection("jdbc:h2:mem:"+uuid+";CREATE=TRUE;DB_CLOSE_ON_EXIT=FALSE"); 
    return (Connection)java.lang.reflect.Proxy.newProxyInstance(
      connection.getClass().getClassLoader(), 
      connection.getClass().getInterfaces(), 
      new MockFailureWrapper(connection)); 
} 
1

私はこれがaspectsを使用するための良い候補だと思います。たとえば。 Springパッケージ全体をポイントカットしたり、失敗したい特定のメソッドをポイントカットするのは非常に簡単です。具体的には、beforeのアドバイスは常にConnectExceptionを投げたり、aroundアドバイスでより高度なアドバイスを行うことができます。

乾杯、

関連する問題