2017-07-19 52 views
2

我正在嘗試爲某些打開數據庫連接並對數據庫執行一些操作的代碼編寫單元測試。我想斷言連接被正確關閉,即使拋出異常也是如此。當試圖使用資源時調用斷言關閉

我要測試的代碼如下所示:

public void methodToTest(final String aName) { 
    final String sqlDeleteStatement = "DELETE FROM " + DB_FULL_TABLE + " WHERE name=?"; 

    try (final Connection connection = this.dataSource.getConnection(); 
     final PreparedStatement deleteStatement = connection.prepareStatement(sqlDeleteStatement);) { 
    connection.setAutoCommit(true); 

    deleteStatement.setString(1, aName); 
    deleteStatement.executeUpdate(); 
    } 
    catch (final SQLException e) { 
    // handle error 
    } 
} 

我目前使用JMock的創建數據源和連接對象實例模擬和仿真,一個例外是在connection.prepareStatement拋出:

public void testConnectionClosed() throws Exception { 
    final Mockery mockery = new Mockery(); 
    final DataSource dataSource = mockery.mock(DataSource.class); 
    final Connection connection = mockery.mock(Connection.class); 

    final String exceptionMessage = "intentionally thrown " + UUID.randomUUID(); 

    mockery.checking(new Expectations() {{ 
     oneOf(dataSource).getConnection(); 
     will(returnValue(connection)); 

     oneOf(connection).prepareStatement(with(any(String.class))); 
     will(throwException(new SQLException(exceptionMessage))); 

     oneOf(connection).close(); 
    }}); 

    final ClassUnderTest cut = new ClassUnderTest(dataSource); 
    cut.methodToTest("someName"); 

    mockery.assertIsSatisfied(); 
} 

我面臨的問題是,測試是綠色和沒有期望connection.close()。沒有期待我看到一個抑制org.jmock.api.ExcpectationError

Suppressed: unexpected invocation: java.sql.Connection1370903230.close() 

但隨着錯誤的嘗試,與資源語句隱含finally塊內提出的測試沒有失敗。

我不想重寫代碼只是爲了讓這個測試有意義,但我想確保正確的資源處理,而且不需要太多關於特定實現細節的知識,比如使用try-with-resource。

有沒有辦法用jMock來實現這一點?


不,我不是要求在圖書館推薦。所以請不要標記爲脫離主題。

回答

1

這裏的關鍵點是:您不一定要驗證隨資源嘗試工作,因爲Java語言規範認爲它應該起作用。如果你沒有找到解決這個問題的解決方案,與jMock一起工作 - 那麼去「下一個最好的事情」。這將是:寫一個測試案例的「好路徑」,確保連接關閉。

含義:你的問題是這個測試是拋出一個異常,這意味着關閉調用是「隱藏」你的。但是當你寫一個測試,其中沒有異常拋出,你應該能夠驗證close()被調用。

而且,當您使用試用資源時,您可以推斷它也將被稱爲壞路徑。當然,這不是很優雅。但這是一個實用的解決方案 - 植根於您正在使用「模糊」嘲笑框架的事實!

因此,real的答案是:使用合理的嘲笑框架。

這有點固執己見,但jmock對生產使用「不合理」 - 只是因爲「沒有人」正在使用它。這似乎是一個「幾乎死亡」的項目。當你轉向jmock site你很容易遇到「死」的鏈接。當你轉向他們的github的存在 - 你會發現自2016年以來只有一小部分提交。無論如何,只有幾個委託人,長時間的提交數量非常接近於零。

當您依賴開源工具來支持您的項目/產品時,您需要確保有一個活躍的用戶和開發社區。因爲當你遇到問題時,你需要答案。當你花費時間獲得使用該工具的技能時,你想避免投注一匹死馬。

TL; DR:

  • 要麼是務實,只測試了 「很好的例子」;希望沒有人是「愚蠢」足以讓試圖與 - 資源投入到舊校園的try/catch
  • 變化到不同的嘲諷框架(例如mockito其中有20 次標籤上所以比JMock的更多的問題)

(不要誤會我的意思:JMock的可能是一個「精」框架 - 但重要的是活力不移動(或移動速度過慢的東西)是你不投入。錢已死技術)

鑑於jmock是一個既定的框架 - 只需考慮「進化的進化」。含義:獲得另一個嘲諷框架的批准;並簡單地開始使用任何東西。這就是我們從EasyMock轉移到Mockito的方式;而且工作很好。

+0

我內部已經提出了對jMock的關注。我們的測試基地非常大,jMock在各地都有使用。由於它在99.9%的用例中工作正常,因此很難爭取框架切換並獲得批准。但是,我可以用mockito編寫一個像上面這樣的測試,並獲得所需的行爲? – dpr

+0

關於測試好案例和進行錯誤案例正確處理的觀點:如果我這樣做了,我會在測試中添加大量不一定成立的假設。如果有人更改了實現並決定不再使用try-with-resource,而是關閉try-block中的連接,那麼好的情況仍然會成功,但連接在錯誤情況下將保持不變。那就是測試不會在所描述的重構中發現錯誤。 – dpr

+0

當然。但是,如果有人打算**故意**的事情,你可以做的事情並不多。如果那個人不知道他在做什麼,那麼他可能會前進並「調整」那個失敗的測試,直到它給你「綠色」。是的,用Mockito或EasyMock編寫這個測試用例應該很簡單。 – GhostCat