虽然以前用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测试,则简洁很多。而且清晰很多。 上面只是在比较少逻辑的时候测试,如果代码逻辑复杂,我觉得写出来的测试代码会更复杂,这有引出,可能维护测试代码的工作比维护代码的工作更累 |