89510091 2009-10-30
EasyMock与Junit的集成测试
EasyMock是一套通过简单的方法对于指定的接口或类生成Mock对象的类库,它能利用对接口或类的模拟来辅助单元测试。Mock方法是单元测试中常见的一种技术,它的主要作用是模拟一些在应用中不容易构造或者比较复杂的对象,比如HttpServletRequest、Connection等,从而把测试与测试边界以外的对象隔离开,真正的形成“单元测试”,而不会因为依赖对象对测试产生影响。
1、使用EasyMock的大体步骤
A.使用EasyMock生成Mock对象;
单个的Mock对象,利用静态导入EasyMock,通过createMock(interfaceName.class)
多个Mock对象,通过ImocksControl管理。
IMocksControlcontrol=EasyMock.createControl();
java.sql.ConnectionmockConnection=control.createMock(Connection.class);
java.sql.StatementmockStatement=control.createMock(Statement.class);
B.设定Mock对象的预期行为和输出;比如一个PreparedStatement的Mock对象pst
expect(pst.executeQuery()).andReturn(rs);
pst.close();
所有实际代码执行的方法,都必须“录制”。D.将Mock对象切换到Replay状态
单个Mock:replay(mockObj)
多个Mcok:control.replay()
E.利用Mock对象方法进行实际单元测试;
Stringres=login.login(conn,name,pas);//con是一个Connection的Mock对象
F.对Mock对象的行为进行验证。
单个Mock:verify(mockObj)
多个Mock:control.verify()
附:利用EasyMock生成数据库连接简单测试示例package demo.mock; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class LoginAction{ public String login(Connection conn, String name, int pas) { PreparedStatement pst = null; ResultSet rs = null; try { String sql = "select * from user where name = ? and pas = ?"; pst = conn.prepareStatement(sql); pst.setString(1, name); pst.setInt(2, pas); rs = pst.executeQuery(); if(rs.next()) { return "登陆成功。"; } else { return "登陆失败。"; } }catch(SQLException e) { e.printStackTrace(); return "抛出异常。"; } finally { try { rs.close(); pst.close(); } catch (SQLException e) { e.printStackTrace(); } } } } package demo.mock; import static org.easymock.EasyMock.createControl; import static org.easymock.EasyMock.expect; import static org.junit.Assert.assertEquals; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import org.easymock.IMocksControl; import org.junit.After; import org.junit.Before; import org.junit.Test; public class LoginActionTest { private LoginAction login; @Before public void init() { login = new LoginAction(); } @After public void destory() { login = null; } @Test public void login() throws SQLException{ String name = "admin"; int pas = 123; //创建Mock对象 IMocksControl control = createControl(); //创建多个Mock对象时通过IMocksControl管理 Connection conn = control.createMock(Connection.class); PreparedStatement pst = control.createMock(PreparedStatement.class); ResultSet rs = control.createMock(ResultSet.class); // 录制信息,即设定Mock对象的预期行为和输出 // 所有Mock对象需要执行的方法都必须录制,如pst.setInt(2, pas)、rs.close()等 String sql = "select * from user where name = ? and pas = ?"; expect(conn.prepareStatement(sql)).andReturn(pst).times(1); pst.setString(1, name); pst.setInt(2, pas); expect(pst.executeQuery()).andReturn(rs); expect(rs.next()).andReturn(true); rs.close(); pst.close(); //录制完成,切换replay状态 control.replay(); //调用实际的方法 String res = login.login(conn, name, pas); String expected = "登陆成功。"; assertEquals(expected, res); //验证 control.verify(); } }
2、重要的概念
在一个完整的测试过程中,一个Mock对象将会经历两个状态:Record状态和Replay状态。Mock对象一经创建,它的状态就被置为Record。在Record状态,用户可以设定Mock对象的预期行为和输出,这些对象行为被录制下来,保存在Mock对象中。
将Mock对象切换到Replay状态
在使用Mock对象进行实际的测试前,我们需要将Mock对象的状态切换为Replay。在Replay状态,Mock对象能够根据设定对特定的方法调用作出预期的响应。将Mock对象切换成Replay状态有两种方式,您需要根据Mock对象的生成方式进行选择。如果Mock对象是通过org.easymock.EasyMock类提供的静态方法createMock生成的(第1节中介绍的第一种Mock对象生成方法),那么EasyMock类提供了相应的replay方法用于将Mock对象切换为Replay状态:
replay(mockResultSet);
如果Mock对象是通过IMocksControl接口提供的createMock方法生成的(第1节中介绍的第二种Mock对象生成方法),那么您依旧可以通过IMocksControl接口对它所创建的所有Mock对象进行切换:
control.replay();
对Mock对象的行为进行验证
在利用Mock对象进行实际的测试过程之后,我们还有一件事情没有做:对Mock对象的方法调用的次数进行验证。
为了验证指定的方法调用真的完成了,我们需要调用verify方法进行验证。和replay方法类似,您需要根据Mock对象的生成方式来选用不同的验证方式。如果Mock对象是由org.easymock.EasyMock类提供的createMock静态方法生成的,那么我们同样采用EasyMock类的静态方法verify进行验证:
verify(mockResultSet);
如果Mock对象是有IMocksControl接口所提供的createMock方法生成的,那么采用该接口提供的verify方法,例如第1节中的IMocksControl实例control:
control.verify();
Mock对象的重用
为了避免生成过多的Mock对象,EasyMock允许对原有Mock对象进行重用。要对Mock对象重新初始化,我们可以采用reset方法。和replay和verify方法类似,EasyMock提供了两种reset方式:(1)如果Mock对象是由org.easymock.EasyMock类中的静态方法createMock生成的,那么该Mock对象的可以用EasyMock类的静态方法reset重新初始化;(2)如果Mock方法是由IMocksControl实例的createMock方法生成的,那么该IMocksControl实例方法reset的调用将会把所有该实例创建的Mock对象重新初始化。
在重新初始化之后,Mock对象的状态将被置为Record状态。
参考:1、http://www.ibm.com/developerworks/cn/opensource/os-cn-easymock/(推荐)
2、http://macrochen.iteye.com/blog/298032