关于EasyMock:
官网:easymock.org
注意:
3.0版本前,使用JDK的动态代理实现Mock对象创建,因此只能对接口进行mock,如果需要对类进行mock,需要使用扩展org.easymock.classextension.EasyMock
3.0后,可以针对接口&类进行mock
EasyMock范例(Service层代码单元测试):
1.工程中引入EasyMock包:
maven工程的话,pom包中添加依赖:
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>3.4</version>
<scope>test</scope>
</dependency>
2.被测对象:
public class UserService{
@Resource
private UserDao userDao;
private String getUserName(String userId)
{
User user = userDao.select(userId);
if (null == user)
{
return "";
}else {
return "offline_" + user.getName();
}
}
}
其中UserService依赖UserDao接口的实现
3.测试代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:CommonUtils.xml")
public class UserServiceTest{
private UserDao userDaoMock = null;
private User userMock = null;
@Resource
private UserService userService;
@Before
public void setUp()
{
// 创建mock对象
userDaoMock = EasyMock.createMock(UserDao.class);
userMock = EasyMock.createMock(User.class);
// mock对象注入被测对象
Field userDaoField = userService.getDeclaredField("userDao");
userDaoField.setAccessible(true);
userDaoField.set(userService,userDaoMock);
}
@Test
public void getUserName()
{
// 设置mock对象的期望值
EasyMock.expect(userMock.getName()).andReturn("testName");
EasyMock.expect(userDaoMock.select("1")).andReturn(userMock);
// mock对象的replay
EasyMock.replay(userMock);
EasyMock.replay(userDaoMock);
// 断言
Assert.assertTrue(userService.getUserName("1").equals("offline_testName"));
// 验证mock对象是否被调用
EasyMock.verify(userMock);
EasyMock.verify(userDaoMock);
}
@After
public void tearDown() throws Exception {
userDaoMock = null;
userMock = null;
}
}
根据官方文档,mock的todolist有:
- Create the mock
- Have it set to the tested class
- Record what we expect the mock to do
- Tell all mocks we are now doing the actual testing
- Test
- Make sure everything that was supposed to be called was called
我们范例中对应是:
1.使用EasyMock生成Mock对象:
userDaoMock = EasyMock.createMock(UserDao.class);
userMock = EasyMock.createMock(User.class);
2.Mock对象注入被测对象:
Field userDaoField = userService.getDeclaredField("userDao");
userDaoField.setAccessible(true);
userDaoField.set(userService,userDaoMock);
3.设定Mock对象的预期行为和输出:
EasyMock.expect(userMock.getName()).andReturn("testName");
EasyMock.expect(userDaoMock.select("1")).andReturn(userMock);
4.将Mock对象切换到Replay状态:
EasyMock.replay(userMock);
EasyMock.replay(userDaoMock);
5.调用Mock对象方法进行单元测试:
Assert.assertTrue(userService.getUserName("1").equals("offline_testName"));
6.确定mock对象有被调用:
EasyMock.verify(userMock);
EasyMock.verify(userDaoMock);
EasyMock进阶:
- 使用IMocksControl管理多个mock对象
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:CommonUtils.xml")
public class UserServiceTest{
private IMocksControl iMocksControl = null;
private UserDao userDaoMock = null;
private User userMock = null;
@Resource
private UserService userService;
@Before
public void setUp()
{
// 创建mock对象
iMocksControl = EasyMock.createControl();
userDaoMock = iMocksControl.createMock(UserDao.class);
userMock = iMocksControl.createMock(User.class);
// mock对象注入被测对象
Field userDaoField = userService.getDeclaredField("userDao");
userDaoField.setAccessible(true);
userDaoField.set(userService,userDaoMock);
}
@Test
public void getUserName()
{
// 设置mock对象的期望值
EasyMock.expect(userMock.getName()).andReturn("testName");
EasyMock.expect(userDaoMock.select("1")).andReturn(userMock);
// mock对象的replay
iMocksControl.replay();
// 断言
Assert.assertTrue(userService.getUserName("1").equals("offline_testName"));
// 验证mock对象是否被调用
iMocksControl.verify();
}
@After
public void tearDown() throws Exception {
userDaoMock = null;
userMock = null;
}
}
- 使用注解
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:CommonUtils.xml")
public class UserServiceTest{
@Rule
private EasyMockRule mocks = new EasyMockRule(this);
private IMocksControl iMocksControl = null;
@Mock
private UserDao userDaoMock = null;
private User userMock = null;
@TestSubject
@Resource
private UserService userService;
...
}
解析:
1.mock对象会被注入到userService对象中,@Mock是需要创建的mock对象,@TestSubject是被测类
2.如果没有下面这段代码设置Junit的rule,需要将测试类的Runner设置为@RunWith(EasyMockRunner.class),当你希望使用别的runner类,但是又需要EasyMock的注解时,使用Junit的rule进行扩展
@Rule
private EasyMockRule mocks = new EasyMockRule(this);