1.EasyMock 简介
Mock 对象的弊端?
手动的构造 Mock 对象会给开发人员带来额外的编码量
为创建 Mock 对象而编写的代码很有可能引入错误
根据现有的接口或类动态生成 Mock 对象,能避免额外的编码工作,同时也降低了引入错误的可能。
EasyMock 是一套用于通过简单的方法对于给定的接口生成 Mock 对象的类库。
提供对接口的模拟,能够通过录制、回放、检查三步来完成大体的测试过程,可以验证方法的调用种类、次数、顺序,可以令 Mock 对象返回指定的值或抛出指定异常。
通过 EasyMock,可以方便的构造 Mock 对象从而使单元测试顺利进行
easymock的官网 https://easymock.org/
2.EasyMock 实例
public class User {
private String id;
private String name;
private int age;
public String getId() {return id;}
public void setId(String id) {this.id = id;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
public User() {super();}
public User(String id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
}
public interface UserService {
User query(String userId);
}
public interface UserDao {
User getById(String userId);
}
public class UserServiceImpl implements UserService {
private UserDao userDao;
public User query(String userId) {
return userDao.getById(userId);
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
定义两个interface:
UserService 和 UserDao, 并给出了实现类UserServiceImpl 。 UserServiceImpl依赖到UserDao,通过setter方法可以注入一个UserDao实现。
使用mock object 技术测试:UserServiceImpl
手动Mock的测试方法
class MockUserDao implements UserDao {
private Map<String, User> users = new HashMap<String, User>();
public void addUser(String userid, User user) {
users.put(userid, user);
}
public User getById(String userId) {
// TODO Auto-generated method stub
return users.get(userId);
}
完整测试方法
public class UserServiceImplTestWithMockObject {
@Test
public void testQuery() {
User expectedUser = new User();
expectedUser.setId("1001");
expectedUser.setAge(30);
expectedUser.setName("user-1001");
MockUserDao mud = new MockUserDao();
mud.addUser("1001", expectedUser);
UserServiceImpl service = new UserServiceImpl();
service.setUserDao(mud);
User user = service.query("1001");
assertNotNull(user);
assertEquals("1001", user.getId());
assertEquals(30, user.getAge());
assertEquals("user-1001", user.getName());
}
}
如果使用EasyMock技术,如何实现,带来多大的方便???
3.EasyMock 模型
3.1、record-replay-verify 模型
record-replay-verify 模型容许记录mock对象上的操作然后重演并验证这些操作。
是目前mock框架领域最常见的模型
几乎所有的mock框架都是用这个模型
3.2、record
UserDao userDao = EasyMock.createMock(UserDao.class);
EasyMock.expect(userDao.getById("1001")).andReturn(expectedUser);
创建mock对象,并期望这个mock对象的方法被调用,同时给出希望这个方法返回的结果。
这就是"记录mock对象上的操作", 同时也会看到"expect"这个关键字。
在record阶段,需要给出的是对mock对象的一系列期望:若干个mock对象被调用,依从给定的参数,顺序,次数等,并返回预设好的结果(返回值或者异常).
** 3.3、replay**
EasyMock.replay(mockUserDao);
UserServiceImpl service = new UserServiceImpl();
service.setUserDao(mockUserDao);
User user = service.query("1001");
在replay阶段,主要测试对象被创建,前面在record阶段创建的相关依赖被关联到主要测试对象,然后执行被测试的方法,以模拟真实运行环境下主要测试对象的行为。
在测试方法执行过程中,主要测试对象的内部代码被执行,同时和相关的依赖进行交互:
以一定的参数调用依赖的方法,获取并处理返回。
期待这个过程如在record阶段设想的交互场景一致,即期望在replay阶段所有在record阶段记录的行为都将被完整而准确的重新演绎一遍,从而到达验证主要测试对象行为的目的。
** 3.4、verify**
n在verify阶段,将验证测试的结果和****交互行为
assertNotNull(user);
assertEquals("1001", user.getId());
assertEquals(30, user.getAge());
assertEquals("user-1001", user.getName());
EasyMock.verify(userDao);
验证结果,即主要测试对象的测试方法返回的结果(对于异常测试场景则是抛出的异常)是否如预期,通常这个验证过程需要自行编码实现
EasyMock.verify(userDao);
验证交互行为,典型如依赖是否被调用,调用的参数,顺序和次数,这部分的验证过程通常是由mock框架来自动完成。
3.5、easymock部分功能说明
*1. 创建mock*对象
UserDao mockUserDao = Easymock.createMock(UserDao.class);
*2. 记录mock*对象期望的行为
Easymock.expect(mockUserDao.getById("1001")).andReturn(expectedUser);
这里记录了mock对象的行为:getById()方法被调用,调用次数为1
(easymock之中如果没有明确指出调用次数,默认为1),参数为"1001",expectedUser将作为返回值。
3. 进入replay阶段
** Easymock.replay(mockU****serDao); **
4. 对mock对象执行验证
Easymock.verify(mockUserDao);
5. 指定期望的调用次数
Easymock.expect(mockUserDao.getById("1001")).andReturn(expectedUser).times(3);
6. 指定抛出期望的异常
Easymock.expect(*mockU*serDao.getById("1001")).andThrow(new RuntimeException("no user exist"));
7. 记录void 方法的行为:
如果mock对象的方法是void,则需要使用expectLastCall():
mockUserDao.someVoidMethod();
Easymock.expectLastCall();
和Easymock.expect()一样,同样支持指定调用次数,抛出异常等:*
Easymock.expectLastCall().times(3);
Easymock.expectLastCall().andThrow(new RuntimeException("some error"));
8. 灵活的参数匹配
Easymock.expect(*mockU*serDao.getById(Easymock.isA(String.class))).andReturn(expectedUser);
类似的还有anyInt(),anyObject(), isNull() , same(), startsWith()等诸多实现。
4.EasyMock 应用
4.1、Easymock对AccountService进行测试
4.2、用Easymock对WebClient的测试
版权归原作者 Pig Pig Cat 所有, 如有侵权,请联系我们删除。