雖然以前用easymock測試過Dao,但那些Dao的實現,要么就hibernate,要么就用spring,而這兩個框架的執行正確與否我們是不用關心的。JDBC是不是也這樣測試了。答案是肯定的。
????? 這幾天要用存儲過程跟jdbc來做個項目,想想也有好長一段時間沒用過JDBC來做項目了。該復習復習了。
????? 前陣子學了easymock,真好現在可以派上用場了。不過在測試的過程中還是遇到了不小問題,想來是自己基礎不好的緣故。
?????? 這次不TDD了,太麻煩了。
?????? 先看看我們要測試的代碼
?????
java 代碼
?
- CallableStatementcstmt?=?null;??
- ????????try?{??
- ????????????cstmt?=?_conn.prepareCall("{call?LUCK_LOAD_COMMON(?,?)}");??
- ????????????cstmt.setString(1,?"1");??
- ????????????cstmt.registerOutParameter(2,?java.sql.Types.VARCHAR);??
- ??
- ????????????cstmt.executeUpdate();??
- ????????????return?cstmt.getString(2);??
- ??
- ????????}?catch?(Exception?e)?{??
- ????????????GxDebug.logException(e);??
- ????????????e.printStackTrace();??
- ????????????return?null;??
- ????????}?finally?{??
- ????????????if?(cstmt?!=?null)??
- ????????????????try?{??
- ????????????????????cstmt.close();??
- ????????????????}?catch?(Exception?e)?{??
- ????????????}??
- ????????}??
? 代碼還挺長的。從上面的代碼我們知道我們必須mock兩個對象進去。一個是Connection, 一個是
CallableStatementcstmt 。
好再看看我們的測試代碼
java 代碼
- conn.prepareCall("{call?LUCK_LOAD_COMMON(?,?)}");??
- ????conControl.setReturnValue(cstmt);??
- ????conControl.replay();??
- ??????
- ????cstmt.setString(1,?"1");??
- ????cstmt.registerOutParameter(2,?java.sql.Types.VARCHAR);??
- ????cstmt.executeUpdate();??
- ????cstmtControl.setReturnValue(1);??
- ????cstmt.getString(2);??
- ????cstmtControl.setReturnValue("5,4,3");??
- ????cstmt.close();??
- ????cstmtControl.replay();??
- ??????
- ??????
- ????String?rusult?=?dao.getNumber();??
- ????Assert.assertEquals("5,4,3",?rusult);??
- ??????
- ????conControl.verify();??
- ????cstmtControl.verify();??
oh,my got!測試代碼比實現代碼還要多。這段代碼能執行嗎?
我想可以的。easymock的原理是記錄-回放的模式。
我想要做的工作是:
1,記錄你mock對象的工作記錄,比如上面的代碼我們mock對象的工作記錄是:
java 代碼
- conn.prepareCall("{call?LUCK_LOAD_COMMON(?,?)}");??
- ????????conControl.setReturnValue(cstmt);??
- ????????cstmt.setString(1,?"1");??
- ????????cstmt.registerOutParameter(2,?java.sql.Types.VARCHAR);??
- ????????cstmt.executeUpdate();??
- ????????cstmtControl.setReturnValue(1);??
- ????????cstmt.getString(2);??
- ????????cstmtControl.setReturnValue("5,4,3");??
- ????????cstmt.close();??
- ??
?如果你工作記錄的代碼要求有返回值的話,那么你必須提供一個自定義的值給它,否則會報錯。比如上面的
?cstmt.getString(2);??????????cstmtControl.setReturnValue("5,4,3");?? //自己定義的返回值,用作以后的比較。
上面的是記錄操作,回放的時候,easymock會把記錄的操作跟你實際的代碼進行比較,如果里面出了什么差錯,那么不好意思你的代碼有問題,請修正后再測試。
如果有興趣可以自己試下。比如如果您
conn.prepareCall("{call LUCK_LOAD_COMMON(?,?)}");
修改為
conn.prepareCall("{call LUCK_LOAD_COMMON(?,?,?)}");
則出現的異常是:
junit.framework.AssertionFailedError:
Unexpected method call prepareCall("{call LUCK_LOAD_COMMON(?,?)}"):
prepareCall("{call LUCK_LOAD_COMMON(?,?)}"): expected: 0, actual: 1
prepareCall("{call LUCK_LOAD_COMMON(?,?,?)}"): expected: 1, actual: 0
現在我總算是對ribbon說對于數據庫的測試還是真實環境的好。 因為你測試的時候你不知道存儲過程是否正確。 而且如果用真實的數據庫測試,相對與mock測試,則簡潔很多。而且清晰很多。 上面只是在比較少邏輯的時候測試,如果代碼邏輯復雜,我覺得寫出來的測試代碼會更復雜,這有引出,可能維護測試代碼的工作比維護代碼的工作更累 |