晦涩的EasyMock和PowerMock
又到了周末,作为程序的我深感苦逼,周末无地可去。。。本来心想到了周末可以好好放松放松了,可是真心无伴无钱。此时的困境怎一个囧字了得。嘿嘿!前面是我的一番抱怨了。下面,切入正题吧。
经过一周的学习,算是对EasyMock和PowerMock有了一点点了解。由于我们公司的开发人员在进行单元测试的时候需要使用到的,而且作为新来的毕业生菜鸟。我开始学期了EasyMock和PowerMock。首先我们需要了解什么是EasyMock和PowerMock。
EasyMock:可以从其名称上面入手,简单的Mock。其主要是进行Mock一些接口,当我们在项目中需要使用别人的模块的东西的时候,而我们又不知道别人的有关接口的具体实现。但是我们又需要使用与之有关的结果。此时EasyMock便可以很好的扮演mock的角色。我们可以把相关的接口实现通过EasyMock.createMock(接口.class)来模拟其实现类。
其EasyMock主要有一下几步:
1:模拟一个接口对象:
UserDao udao=EasyMock.createMock(UserDao.class)此时Mock对象处于Record状态
2:设定Mock对象的预期行为和希望得到的结果
/**
* EasyMock.expect()方法后面必定跟着返回值
*/
EasyMock.expect(udao.getById(1001)).andReturn(expectedUser);
3:replay()重置mock对象
EasyMock.replay(udao)
4:进行验证
EasyMock.verify(udao)
EasyMock的使用核心路线主要是:Record------->Replay---------->verify三种状态的切换
以下附上一个完整的代码:
package com.test;
import junit.framework.Assert;
import org.easymock.EasyMock;
import org.junit.Test;
import com.bean.User;
import com.dao.UserDao;
import com.service.impl.UserServiceImpl;
/**
* 使用Mock对象模拟测试的时候,equals(),hashcode(),toString()三个函数无法更改其行为
* @author Clark
* class mock除了以上三个限制外还有final,private方法都不能被mock
* 对于静态方法,easymock也无法mock其行为
*/
public class UserServiceImplTest extends Assert{
@Test
public void testQuery(){
User expectedUser=new User(1001,"clark");
UserDao udao=EasyMock.createMock(UserDao.class);
/**
* EasyMock.expect()方法后面必定跟着返回值
*/
//此处的1001相当于数据库中表的别名。。我们可以随便取名,与前面的1001无关系
EasyMock.expect(udao.getById(1001)).andReturn(expectedUser);
/**
* 如果mock对象的方法是void,则需要使用expectLastCall()方法
*/
// udao.sayHi();
// EasyMock.expectLastCall();
EasyMock.replay(udao);
UserServiceImpl service=new UserServiceImpl();
service.setUserDao(udao);
User u=service.query(1001);
assertNotNull(u);
assertEquals(expectedUser,u);
EasyMock.verify(udao);
}
}
User类package com.bean;
public class User {
public int userId;
public String userName;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public User(int userId, String userName) {
this.userId = userId;
this.userName = userName;
}
public User() {
}
}
Mock的UserDao接口
package com.dao;
import com.bean.User;
public interface UserDao {
public User getById(int userId);
public void sayHi();
}
package com.service;
import com.bean.User;
public interface UserService {
User query(int userId);
}
package com.service.impl;
import com.bean.User;
import com.dao.UserDao;
import com.service.UserService;
public class UserServiceImpl implements UserService{
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public User query(int userId) {
return userDao.getById(userId);
}
public void print(){
userDao.sayHi();
}
}
PowerMock是EasyMock的一个扩展,加入了static,final,private,以及constructor的Mock功能。但是PowerMock并没有继承EasyMock的一些测试功能,所以不能取代EasyMock,而单独使用。在很多时候必须要PowerMock和EasyMock相互结合,以及加上WhiteBox,才能更好实现测试。
1. 必不可少的一步:添加测试运行器@RunWith(PowerMockRunner.class),如果没有添加这个运行器,则使用的是默认的JUnit4.class。在PrepareForTest中加入测试class。@PrepareForTest(测试.class)
Mock构造器函数
public class A{
public void doA(){
new B();
}
}
public class B{
public B(){
System.out.println("can't be here!");
}
}
测试classA中的doA方法:
@RunWith(PowerMockRunner.class)
@PrepareForTest({A.class})
public class ATest {
@Test
public void testdoA() throws Exception {
B mockB = PowerMock.createMock( B.class );
PowerMock.expectNew( B.class ).andReturn(mockB);
A testA = new A();
PowerMock.replayAll();
testA.doA();
PowerMock.verifyAll();
}
}
但是在单元测试testdoA()方法的时候总是会报:
testdoA()
Unrooted Tests
initializationError
心里好纳闷,查了好多资料都没解决。希望哪位高手看到了帮小弟解决一下
3.static
测试static方法的时候必须要加上@PrepareForTest(静态方法.class),否则就会抛出java.lang.IllegalStateException: no last call on a mock available异常。如果有多个class,用{},例如@PrepareForTest({A.class,B.class})
public class A{
public void doA(){
B.doB();
}
}
public class B{
public static String doB() {
return ("can't be here !");
}
}
测试classA中的doA方法:
@RunWith(PowerMockRunner.class)
@PrepareForTest({A.class, B.class})
public class ATest {
@Test
public void testdoA() throws Exception {
PowerMock.mockStatic( B.class );
EasyMock.expect(B.doB()).andReturn("Mocked !");
A testA = new A();
PowerMock.replayAll();
assertEquals("Mock not complete !", testA.doA(), "Mocked !");
PowerMock.verifyAll();
}
}
4.mock类中的Field
一个好的Field应该有getter和setter,但是代码中没有,我们也可以用WhiteBox来Mock掉Field。
public class A{
private String C;
public A(){
C = "Can't be here !";
}
public String doA(){
return C;
}
}
测试A中的doA方法
@RunWith(PowerMockRunner.class)
@PrepareForTest({A.class, B.class})
public class ATest {
@Test
public void testdoA(){
A testA = new A();
String mockC = "Mocked !";
Whitebox.setInternalState( testA, "C", mockC );
assertEquals("Mock not complete !", testA.doA(), "Mocked !");
}
}