确定性地使DB失败以进行测试

Wil*_*ill 5 java testing

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

我想测试一下,如果数据库不可用,我的服务会返回相应的错误代码(区分临时和永久问题,例如HTTP 500和503).

为了测试,我的应用程序连接到嵌入式本地内存中的h2数据库; 应用程序没有意识到这一点,只有我的集成测试.

如何确定性地对数据库进行写入失败,例如挂钩到提交并使它们抛出自定义SQLException?我希望测试代码中的全局"数据库不可用"布尔值影响所有连接,并使我的应用程序运行其重新连接逻辑.

(我已经通过代理开始Connection,然后将一个if(failFlag) throw new MySimulateFailureException()commit(),但这并没有赶上PreparedStatement.executeUpdate();之前,我走上代理所述PreparedStatement!太-它有很多的方法-我想教一个更好的方法...)

Wil*_*ill 0

我最终制作了自己的 Java 反射包装器来拦截Connection.commitPreparedStatement.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));
}
Run Code Online (Sandbox Code Playgroud)