5

私はデータベースに多くを使用するJavaアプリケーションを持っていjava.sql.Connectionます。

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

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

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

(私はプロキシConnectionと入力から始めましif(failFlag) throw new MySimulateFailureException()commit();しかしこれはうまくいきませんでしたPreparedStatement.executeUpdate();私もプロキシに着手する前にPreparedStatement-それはたくさんの方法です!-私はより良い方法を教えられたいです...)

4

2 に答える 2

1

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

乾杯、

于 2012-10-22T10:31:19.390 に答える
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));
}
于 2012-10-22T12:47:08.930 に答える