2012-10-22 93 views
5

我有一個Java應用程序,使用大量java.sql.Connection到數據庫。使數據庫失敗確定測試

我想測試一下,如果數據庫不可用,我的服務會返回相應的錯誤代碼(區分臨時和永久性問題,例如HTTP 500和503)。

爲了測試,我的應用程序連接到嵌入式本地內存中的h2數據庫;應用程序不知道這一點,只有我的集成測試是。

如何確定性地寫入數據庫失敗勾入提交,並讓他們拋出自定義SQLException?我想要測試代碼中的全局'數據庫不可用'布爾值,它會影響所有連接並使我的應用程序執行其重新連接邏輯。

(我已經通過進行代理Connection,然後將一個if(failFlag) throw new MySimulateFailureException()commit()開始,但是這並沒有趕上PreparedStatement.executeUpdate();之前,我走上代理所述PreparedStatement太 - 它有很多的方法 - 我想教!更好的方法...)

+2

這聽起來可能很傻,但爲什麼不停止數據庫服務?或者阻止防火牆上的端口來拒絕一點點流量? – Serdalis

+2

我通常使用上面概述的代理路由。如果有人有更好的方法,我會有興趣聽到它。 – Keppil

回答

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)); 
} 
1

我認爲這是一個很好的候選人使用aspects。用例如。 Spring這是非常容易的切入整個包或只是某些方法,你希望失敗 - 具體而言,你可以有一個before建議總是拋出ConnectException或做一些更先進的around建議。

乾杯,