问题描述
限时送ChatGPT账号..我有一个 Java 应用程序,它使用大量 java.sql.Connection
到数据库.
I have a Java application that uses lots of java.sql.Connection
to a database.
我想测试一下,如果数据库不可用,我的服务会返回适当的错误代码(区分临时问题和永久性问题,例如 HTTP 500 和 503).
I want to test that, if the database is unavailable, my services return the appropriate error codes (distinguishing between temporary and permanent problems e.g. HTTP 500 and 503).
为了测试,我的应用程序连接到嵌入式、本地、内存中的 h2 数据库;应用程序不知道这一点,只有我的集成测试是.
For testing, my application connects to an embedded, local, in-memory h2 database; the application is not aware of this, only my integration test is.
我怎样才能确定性地使写入数据库失败,例如挂钩提交并让它们抛出自定义 SQLException
?我想要测试代码中的全局数据库不可用"布尔值影响所有连接并使我的应用程序执行其重新连接逻辑.
How can I make writes to the database fail deterministically, e.g. hook into commits and make them throw a custom SQLException
? I want a global 'database is unavailable' boolean in the test code that affects all connections and makes my application exercise its reconnect logic.
(我已经开始代理 Connection
并在 commit()
中放置一个 if(failFlag) throw new MySimulateFailureException()
; 但这并没有抓住 PreparedStatement.executeUpdate()
; 在我开始代理 PreparedStatement
之前 - 它有很多方法! - 我想被教导更好的方法...)
(I had started by proxying Connection
and putting an if(failFlag) throw new MySimulateFailureException()
in commit()
; but this didn't catch PreparedStatement.executeUpdate()
; before I embark on proxying the PreparedStatement
too - its a lot of methods! - I'd like to be taught a better way...)
推荐答案
我最终制作了自己的 Java 反射包装器来拦截 Connectionmit
和 PreparedStatement.execute...
方法.
I ended up making my own Java reflection wrapper that intercepts Connectionmit
and the PreparedStatement.execute...
methods.
我在DBFactory"类中的最终代码:
My final code in my 'DBFactory' class:
@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));
}
这篇关于使数据库确定性地失败以进行测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
更多推荐
[db:关键词]
发布评论