2012-10-22 3 views
5

Tôi có một ứng dụng Java sử dụng rất nhiều java.sql.Connection đến một cơ sở dữ liệu.Làm cho DB thất bại về mặt xác định để thử nghiệm

Tôi muốn kiểm tra, nếu cơ sở dữ liệu không khả dụng, dịch vụ của tôi trả lại mã lỗi thích hợp (phân biệt giữa các vấn đề tạm thời và vĩnh viễn, ví dụ: HTTP 500 và 503).

Để thử nghiệm, ứng dụng của tôi kết nối với cơ sở dữ liệu h2 được nhúng, cục bộ, trong bộ nhớ; ứng dụng không nhận thức được điều này, chỉ thử nghiệm tích hợp của tôi là.

Tôi làm cách nào để ghi vào cơ sở dữ liệu không xác định, ví dụ: móc vào cam kết và làm cho họ ném một tùy chỉnh SQLException? Tôi muốn một boolean 'cơ sở dữ liệu không có sẵn' toàn cầu trong mã kiểm tra có ảnh hưởng đến tất cả các kết nối và làm cho ứng dụng của tôi thực hiện logic kết nối lại của nó.

(Tôi đã bắt đầu bởi proxy Connection và đưa một if(failFlag) throw new MySimulateFailureException() trong commit(); nhưng điều này không bắt PreparedStatement.executeUpdate(); trước khi tôi bắt tay vào proxy các PreparedStatement quá - rất nhiều của phương pháp - Tôi muốn được giảng dạy! một cách tốt hơn ...)

+2

này nghe có vẻ ngớ ngẩn, nhưng tại sao không dừng dịch vụ cơ sở dữ liệu? hoặc chặn cổng trên tường lửa để từ chối lưu lượng truy cập cho một chút? – Serdalis

+2

Tôi thường đi theo tuyến đường proxy mà bạn phác thảo ở trên. Nếu có ai có cách tiếp cận tốt hơn thì tôi sẽ thích nghe nó. – Keppil

Trả lời

0

tôi đã kết thúc làm riêng Java phản ánh wrapper của tôi sẽ chặn Connection.commitPreparedStatement.execute... phương pháp.

mã cuối cùng của tôi trong lớp 'DBFactory' của tôi:

@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

Tôi nghĩ đây là một ứng cử viên tốt cho việc sử dụng aspects. Với ví dụ. Spring nó là vô cùng dễ dàng để cắt giảm toàn bộ gói hoặc chỉ một số phương pháp mà bạn muốn thất bại - đặc biệt bạn có thể có một lời khuyên before luôn ném một ConnectException hoặc làm điều gì đó tiên tiến hơn với tư vấn around.

Chúc mừng,