EasyMock与Junit的集成测试

来源:互联网 发布:外国人 汉字 知乎 编辑:程序博客网 时间:2024/06/08 00:37

EasyMock与Junit的集成测试

EasyMock 是一套通过简单的方法对于指定的接口或类生成 Mock 对象的类库,它能利用对接口或类的模拟来辅助单元测试。Mock 方法是单元测试中常见的一种技术,它的主要作用是模拟一些在应用中不容易构造或者比较复杂的对象,比如HttpServletRequest、Connection等,从而把测试与测试边界以外的对象隔离开,真正的形成“单元测试”,而不会因为依赖对象对测试产生影响。

1、使用EasyMock的大体步骤

A.使用 EasyMock 生成 Mock 对象;
单个的Mock对象,利用静态导入EasyMock,通过createMock(interfaceName.class)
多个Mock对象,通过ImocksControl管理。
IMocksControl control = EasyMock.createControl();
java.sql.Connection mockConnection = control.createMock(Connection.class);
java.sql.Statement mockStatement = 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 对象方法进行实际单元测试;
String res = login.login(conn, name, pas); //con是一个Connection的Mock对象
F.对 Mock 对象的行为进行验证。
单个Mock:verify(mockObj) 
多个Mock:control.verify()


附:利用EasyMock生成数据库连接简单测试示例

Java代码 复制代码
  1. package demo.mock;   
  2.   
  3. import java.sql.Connection;   
  4. import java.sql.PreparedStatement;   
  5. import java.sql.ResultSet;   
  6. import java.sql.SQLException;   
  7.   
  8.   
  9. public class LoginAction{   
  10.        
  11.     public String login(Connection conn, String name, int pas) {   
  12.            
  13.         PreparedStatement pst = null;   
  14.         ResultSet rs = null;   
  15.            
  16.         try {   
  17.             String sql = "select * from user where name = ? and pas = ?";   
  18.             pst = conn.prepareStatement(sql);   
  19.             pst.setString(1, name);   
  20.             pst.setInt(2, pas);   
  21.             rs = pst.executeQuery();   
  22.                
  23.             if(rs.next()) {   
  24.                 return "登陆成功。";   
  25.             } else {   
  26.                 return "登陆失败。";   
  27.             }   
  28.                
  29.         }catch(SQLException e) {   
  30.             e.printStackTrace();   
  31.             return "抛出异常。";   
  32.         } finally {        
  33.             try {   
  34.                 rs.close();   
  35.                 pst.close();   
  36.             } catch (SQLException e) {   
  37.                 e.printStackTrace();   
  38.             }   
  39.         }   
  40.     }   
  41.   
  42. }   
  43.   
  44.   
  45. package demo.mock;   
  46.   
  47. import static org.easymock.EasyMock.createControl;   
  48. import static org.easymock.EasyMock.expect;   
  49. import static org.junit.Assert.assertEquals;   
  50.   
  51. import java.sql.Connection;   
  52. import java.sql.PreparedStatement;   
  53. import java.sql.ResultSet;   
  54. import java.sql.SQLException;   
  55.   
  56. import org.easymock.IMocksControl;   
  57. import org.junit.After;   
  58. import org.junit.Before;   
  59. import org.junit.Test;   
  60.   
  61. public class LoginActionTest {   
  62.        
  63.     private LoginAction login;   
  64.        
  65.     @Before  
  66.     public void init() {   
  67.         login = new LoginAction();   
  68.     }   
  69.        
  70.     @After  
  71.     public void destory() {   
  72.         login = null;   
  73.     }   
  74.   
  75.     @Test  
  76.     public void login() throws SQLException{   
  77.         String name = "admin";   
  78.         int pas = 123;   
  79.            
  80.         //创建Mock对象   
  81.         IMocksControl control = createControl(); //创建多个Mock对象时通过IMocksControl管理   
  82.   
  83.         Connection conn = control.createMock(Connection.class);   
  84.         PreparedStatement pst = control.createMock(PreparedStatement.class);   
  85.         ResultSet rs = control.createMock(ResultSet.class);   
  86.   
  87.         // 录制信息,即设定Mock对象的预期行为和输出   
  88.         // 所有Mock对象需要执行的方法都必须录制,如pst.setInt(2, pas)、rs.close()等   
  89.         String sql = "select * from user where name = ? and pas = ?";   
  90.         expect(conn.prepareStatement(sql)).andReturn(pst).times(1);     
  91.            
  92.         pst.setString(1, name);   
  93.         pst.setInt(2, pas);   
  94.            
  95.         expect(pst.executeQuery()).andReturn(rs);   
  96.         expect(rs.next()).andReturn(true);   
  97.            
  98.            
  99.         rs.close();   
  100.         pst.close();   
  101.            
  102.         //录制完成,切换replay状态   
  103.         control.replay();   
  104.            
  105.         //调用实际的方法   
  106.         String res = login.login(conn, name, pas);   
  107.         String expected = "登陆成功。";   
  108.         assertEquals(expected, res);   
  109.            
  110.         //验证   
  111.         control.verify();   
  112.        
  113.     }   
  114.   
  115. }  





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.javaeye.com/blog/298032

原创粉丝点击