准本工作:
测试代码主要参考: http://easymock.org/EasyMock3_0_Documentation.html
基本概念:
一 . mock和stub的相同点和不同点?
在Manning Junit in Action一书中是这样描述的:
Mocks replace the objects with which your
methods under test collaborate, offering a layer of isolation.
In that sense, they’re similar to stubs.
But this is where the similarity ends, because mocks don’t implement any
logic: they’re empty shells that provide methods to let the tests control the behavior of
all the business methods of the faked class.
详细的来讲
1.相同点:
mock和stub都可以用来对系统(或者将粒度放小为模块,单元)进行隔离。
2.不同点:待补充
Lifecycle
Test lifecycle with stubs:
- Setup - Prepare object that is being tested and its stubs collaborators.
- Exercise - Test the functionality.
- Verify state - Use asserts to check object's state.
- Teardown - Clean up resources.
Test lifecycle with mocks:
- Setup data - Prepare object that is being tested.
- Setup expectations - Prepare expectations in mock that is being used by primary object.
- Exercise - Test the functionality.
- Verify expectations - Verify that correct methods has been invoked in mock.
- Verify state - Use asserts to check object's state.
- Teardown - Clean up resources.
三.easymock的基本用法
mock一般都有三个阶段,分别是 record,replay,verify。即首先记录mock对象上的操作,然后重演这些操作,最后验证这些操作。
在mock对象调用replay()方法之前是记录mock上的操作阶段。在调用replay()方法之后,才表现出mock对象的行为,并检查这些期望的操作是否真正的被调用。
要获得一个Mock对象,需要三个步骤:
- 使用接口创建一个mock对象
- 记录期望的行为(record the expected behavior)
- 将mock对象切换到replay状态,重演期望的行为
下面使用一个最常用的例子来展示一下mock的基本用法:
实体类User,DAO层接口UserDao,Service层接口UserService,测试对象Service的各个方法是否正确,service所需依赖UserDao,所以需要mock出UserDao对象,用来隔离层,专注于service层的单元测试。类图如下:
User对象:
public class User {
private int id;
private String name;
private String age;
public User(){}
public User(int id,String name,String age){
this.id=id;
this.name=name;
this.age=age;
}
//省略getter and setter方法
public void say(){
System.out.println(String.format("%d %s %s ",id,name,age));
}
}
UserDao接口:
public interface UserDao {
User getUserById(int id);
int count();
public String getUserAddress() throws Exception;
}
UserService类,注意这里为了简单,没有使用接口,而是直接使用类代替
public class UserService {
private UserDao userDao;
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public String getUserNameById(int id){
String username=userDao.getUserById(id).getName();
return username;
}
public int count(){
return userDao.count();
}
public User getUser(int id){
return userDao.getUserById(id);
}
public String getUserAddress(int id) throws Exception{
return userDao.getUserAddress();
}
}
接下来是主要的测试代码:
package easymock;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* Created by superman on 14-1-12.
*/
public class UserServiceTest {
private UserService userService;
private UserDao userDaoMock;
private User user;
@Before
public void setUp(){
user=new User(1,"tom","20");
userService=new UserService();
userDaoMock=createMock(UserDao.class);
}
@Test
public void testGetNameById(){
expect(userDaoMock.getUserById(1)).andReturn(user);
replay(userDaoMock);
userService.setUserDao(userDaoMock);
String name=userService.getUserNameById(1);
assertEquals("tom",name);
verify(userDaoMock);
}
@Test
public void testRepeateCall(){
expect(userDaoMock.getUserById(1)).andReturn(user).times(2);
replay(userDaoMock);
userService.setUserDao(userDaoMock);
String name=userService.getUserNameById(1);
name=userService.getUserNameById(1);
verify(userDaoMock);
assertEquals("tom",name);
}
@Test
public void testReturnValue(){
// expect(userDaoMock.getUserById(1)).andReturn(user);
userDaoMock.getUserById(lt(2));
expectLastCall().andReturn(user);
replay(userDaoMock);
userService.setUserDao(userDaoMock);
User user=userService.getUser(1);
assertNotNull(user);
verify(userDaoMock);
}
@Test
@Ignore
public void testException(){
try {
expect(userDaoMock.getUserAddress()).andThrow(new Exception("no address attribute"));
replay(userDaoMock);
userService.setUserDao(userDaoMock);
userService.getUserAddress(1);
verify(userDaoMock);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Tip:mock创建的构造方法
createMock(String name, Class claz);
createMock(Class claz);
如果使用第二种,如果测试结果没有预期的,那么会出现如下提示:
java.lang.AssertionError:
Expectation failure on verify:
read(): expected: 7, actual: 0
如果使用第一种,则会出现如下提示:
java.lang.AssertionError:
Expectation failure on verify:
name.read(): expected: 7, actual: 0
红色部分是区别,所以使用第一种更好,标注了提示。
测试代码主要参考: http://easymock.org/EasyMock3_0_Documentation.html