最近老大让我写单元测试,找到这篇文章,阅读后收获很多,故转之。java
《easymock使用准备》
一、引包
在maven的pom.xml加入依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>3.0</version>
<scope>test</scope>
</dependency>
二、 要测试的类
新建 User类。
public class User {
String type;
}
新建 UserDao接口,里面有个insertUser(User user)方法。
public interface UserDao {
public boolean insertUser(User user);
}
新建 UserService类,里面有个registerUser(User user)方法。
public class UserServive {
private UserDao userDao;
public boolean registerUser(User user){
if (user.type.equals("vip")){
return userDao.insertUser(user);
}else {
System.out.println("only vip can be registered!");
Return false;
}
}
}
咱们要测试 UserService的registerUser(User user)方法,可是这个方法依赖于UserDao的insertUser(User user)方法。咱们假设UserDao这个接口如今还没写好,可是如今又想测UserService的方法逻辑,可它又依赖于UserDao,这可怎么测试?这时候就能够用mock技术啦。
测试代码以下:
import junit.framework.TestCase;
import static org.easymock.EasyMock.*;
public class UserServiceTest extends TestCase{
private UserDao userDao;
private UserService userService = new UserService();
public void testRegisterUser() {
User user = new User();
user.type = "vip";
userDao = createMock(UserDao.class);
expect(userDao.insertUser(user)).andReturn(true);
replay(userDao);
userService.setUserDao(userDao);
assertEquals(true, userService.registerUser(user));
verify(userDao);
}
}
java单元测试 easyMock 使用总结
EasyMock
java
单元测试
1、 easymock使用准备
引包
在maven的pom.xml加入依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>3.0</version>
<scope>test</scope>
</dependency>
二、 要测试的类
新建 User类。
public class User {
String type;
}
新建 UserDao接口,里面有个insertUser(User user)方法。
public interface UserDao {
public boolean insertUser(User user);
}
新建 UserService类,里面有个registerUser(User user)方法。
public class UserServive {
private UserDao userDao;
public boolean registerUser(User user){
if (user.type.equals("vip")){
return userDao.insertUser(user);
}else {
System.out.println("only vip can be registered!");
Return false;
}
}
}
咱们要测试 UserService的registerUser(User user)方法,可是这个方法依赖于UserDao的insertUser(User user)方法。咱们假设UserDao这个接口如今还没写好,可是如今又想测UserService的方法逻辑,可它又依赖于UserDao,这可怎么测试?这时候就能够用mock技术啦。
测试代码以下:
import junit.framework.TestCase;
import static org.easymock.EasyMock.*;
public class UserServiceTest extends TestCase{
private UserDao userDao;
private UserService userService = new UserService();
public void testRegisterUser() {
User user = new User();
user.type = "vip";
userDao = createMock(UserDao.class);
expect(userDao.insertUser(user)).andReturn(true);
replay(userDao);
userService.setUserDao(userDao);
assertEquals(true, userService.registerUser(user));
verify(userDao);
}
}
《easymock使用的通常步骤》
一、 接口/类
easymock class extension的使用方式和普通的interface mock彻底一致,基本上easymock中有的功能easymock class extension都一样提供,并且全部的类名和方法名都保持一致。
惟一的差别在于,easymock class extension的java package和easymock不一样,easymock是
org.easymock.*, 而 easymock class extension是org.easymock.classextension.*,典型如
org.easymock.classextension.Easymock 对应 org.easymock.Easymock。另外在发布时,二者是分开发布的,easymock.jar 和 easymockclassextension.jar,须要根据须要分别导入,或者必要时同时导入。
不过3.0版本已经没有这个问题,接口与类是同样的。
《record-replay-verify 模型》
一、建立mock对象
userDao = createMock(UserDao.class);
二、记录mock对象指望的行为
expect(userDao.insertUser(user)).andReturn(true);
咱们指望这个mock对象的方法被调用,同时给出咱们但愿这个方法返回的结果。这就是所谓的"记录mock对象上的操做", 同时咱们也会看到"expect"这个关键字。总结说,在record阶段,咱们须要给出的是咱们对mock对象的一系列指望:若干个mock对象被调用,依从咱们给定的参数,顺序,次数等,并返回预设好的结果(返回值或者异常).
三、进入replay阶段
replay(userDao);
在replay阶段,咱们关注的主要测试对象将被建立,以前在record阶段建立的相关依赖被关联到主要测试对象,而后执行被测试的方法,以模拟真实运行环境下主要测试对象的行为。
四、对mock对象执行验证
verify(userDao);
验证交互行为,典型如依赖是否被调用,调用的参数,顺序和次数等。
《easymock更多使用》
抛出异常
expect(userDao. insertUser (user)).andThrow(new SQLException("ID conflicts!"));
调用次数
调用3次:expect(userDao. insertUser (user)).andReturn(true).times(3);
这里有一个官网文档中的例子
expect(mock.voteForRemoval("Document"))
.andReturn((byte) 42).times(3)
.andThrow(new RuntimeException()).times(4)
.andReturn((byte) -42);
对于mock.voteForRemoval("Document")方法的调用,.andReturn((byte) 42).times(3) 代表前3次调用将返回42,.andThrow(new RuntimeException()).times(4)表示随后的4次调用(第4,5,6,7次)都将抛出异常,andReturn((byte) -42)表示第8次调用时将返回-42。
调用void方法
若是mock对象的方法是void,则须要使用expectLastCall():
userDao.someVoidMethod();
Easymock.expectLastCall();
和Easymock.expect(***)同样,一样支持指定调用次数,抛出异常等:
调用次序
Mock对象类型有三种
● Normal — EasyMock.createMock() 默认mock出来的都是这个类型,只关心调用方法的参数,不关心调用的次序。
● Strict — EasyMock.createStrictMock(): 当调用方法有次序要求的时候须要mock这个类型。
● Nice — EasyMock.createNiceMock(): 调用到不指望的方法时不会使测试失败,若是原方法返回的类型是number的 它就会返回0,若是是boolean 它会返回false,若是是object它会返回null.
参数匹配
// expect(userDao.insertUser(user)).andReturn(true);
expect(userDao.insertUser(EasyMock.<User>anyObject())).andReturn(true);
anyInt()、anyShort()、anyByte()、anyLong()、anyFloat()、anyDouble()、anyBoolean()、 matches(正则表达式)
Capture的使用
若是方法的参数实在没法预先肯定,咱们可使用capture。好比UserService 有这么个方法:
public boolean registerVIP(){
User user = new User();
user.type = "VIP";
return userDao.insertUser(user);
}
当咱们mock userDao的insertUser(user)方法时,咱们没法肯定他的参数会是什么样子的,由于参数是咱们要测试的registerVIP这个方法new出来给他的,咱们能够假定insertUser的方法逻辑的正确的,可是参数是registerVIP传给他的,因此咱们得验证参数的正确性。
public void testRegisterVIP(){
userDao = createMock(UserDao.class);
Capture<User> captureUser = new Capture<User>();
expect(userDao.insertUser(capture(captureUser))).andReturn(true).times(2);
replay(userDao);
userService.setUserDao(userDao);
userService.registerVIP();
assertEquals("VIP", captureUser.getValue().type); //验证捕捉到的参数是否正确
assertEquals(true, userService.registerVIP());//验证最后的结果
verify(userDao);
}
《对象重用》
为了不生成过多的 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 状态。
《多个mock 用 MocksControl》
当咱们须要mock一系列对象的时候,若是每一个都单独去mock很麻烦, 这种状况下能够考虑使用MocksControl来简化代码:
IMocksControl mocksControl = createControl();
IMyInterface1 mock1 = mocksControl.createMock(IMyInterface1.class);
IMyInterface2 mock2 = mocksControl.createMock(IMyInterface2.class);
IMyInterface3 mock3 = mocksControl.createMock(IMyInterface3.class);
...
mocksControl.replay();
mocksControl.verify();
mocksControl.reset();
《Class mocking的限制》
1) 不能mock类的 final方法。若是final方法被调用,则只能执行原有的正常代码。
2) 不能mock类的static 方法。
3) 一样若是private方法被调用,只能执行原有的正常代码。
4) 不能mock类的一些特殊方法: equals(), toString()和hashCode().缘由是easymock在实现是为每一个class mock对象提供了内建的以上三个方法。须要强调的是,对于基于interface的mock,这个限制也是一样存在的,即便以上三个方式是interface定义的一部分。
5) 在使用时须要避开这种场景,或者组合使用其余的mock 框架好比jmockit来mock private方法和final方法。正则表达式