5

我有一个使用大量java.sql.Connection数据库的 Java 应用程序。

我想测试一下,如果数据库不可用,我的服务会返回适当的错误代码(区分临时问题和永久问题,例如 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

我最终制作了自己的拦截Connection.commitPreparedStatement.execute...方法的 Java 反射包装器。

我在“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 回答