Easymock和Powermock
Easymock
Mock对象用于在单元测试中模拟一些难以构造或者比较复杂的对象,从而把测试环境和外界环境隔开,easymock默认只支持模拟接口对象
1. 引入Easymock的jar包
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>3.6</version>
<scope>test</scope>
</dependency>
2. 要模拟的接口
public interface Calculator {
public int add(int a,int b);
public int subtract(int a, int b);
public int multiply(int a, int b);
public int divide(int a, int b);
}
3. 被测试的类,调用了未实现的接口
public class ClassToEasyMock {
private Calculator calculator;
public int methodToTest(){
int a = calculator.add(2,2);
int b = calculator.divide(2,2);
int c = calculator.multiply(2,2);
int d = calculator.subtract(2,2);
return a+b+c+d;
}
public Calculator getMock() {
return calculator;
}
public void setMock(Calculator calculator) {
this.calculator = calculator;
}
}
4. 测试类
public class ClassToEasyMockTest {
@Test
public void testEasyMock() {
//1.创建mock对象
Calculator mock = EasyMock.createMock(Calculator.class);
//2.设置预期的函数行为
EasyMock.expect(mock.add(2,2)).andReturn(4);
EasyMock.expect(mock.divide(2,2)).andReturn(1);
EasyMock.expect(mock.multiply(2,2)).andReturn(4);
EasyMock.expect(mock.subtract(2,2)).andReturn(0);
//3.重放
EasyMock.replay(mock);
//实例对象验证
ClassToEasyMock classToEasyMock = new ClassToEasyMock();
classToEasyMock.setMock(mock);
assertEquals(9,classToEasyMock.methodToTest());
//4.验证mock对象
EasyMock.verify(mock);
}
}
Easymock的使用步骤
1. 创建mock对象
Calculator mock = EasyMock.createMock(Calculator.class);
如果有多个mock对象,可以使用EasyMock.createControl()方法
IMocksControl control = EasyMock.createControl();
control.createMock(A.class);
control.createMock(B.class);
2. 录制(设置函数的预期返回值)
(1) 有返回值
EasyMock.expect(mock.add(2,2)).andReturn(4);
(2) 没有返回值
EasyMock.expectLastCall(mock.mthod(arguments));
(3) 如果期望抛出异常
EasyMock.expect(mock.divide(3,0)).andThrow(new ArithmeticException());
(4) 预期调用方法的次数
EasyMock.expect(mock.add(2,2)).andReturn(4).once();
EasyMock.expect(mock.add(2,2)).andReturn(4).times(3);
EasyMock.expect(mock.add(2,2)).andReturn(4).anyTimes();
3. 重放
EasyMock.replay(mock);
control.repaly();
4. 验证
EasyMock.verify(mock);
control.verify();
PowerMock
PowerMock是对EasyMock的扩展,PowerMock通过自定义类加载器和修改字节码来模拟private函数,static函数,final函数以及构造函数,
1. 引入PowerMock的jar包
<properties>
<powermock.version>1.6.4</powermock.version>
</properties>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
2. PowerMock注解
(1)@RunWith(PowerMockRunner.class)
指定PowerMock运行器,注意导入的是:org.powermock.modules.junit4.PowerMockRunner
而不是:org.powermock.modules.junit4.legacy.PowerMockRunner
(2)@PrepareForTest({ClassToMock.class})
指定要运行的类,使用PowerMock模拟私有,静态,final和构造方法时都需要修改字节码,需要将方法所在的类加入到PrepareForTest()里去。
(3)@PowerMockIgnore(“javax.management.*”)
解决不加时出现的classloader错误
(4)@Mock
创建mock对象,对象的所有方法为空,即不是真实的方法
普通方法:ClassToMock mock = Powermockito.mock(ClassToMock.class)
(5)@Spy
Spy注解的mock对象必须使用new方法手动创建,具有真实的方法和返回值
普通方法:ClassToMock mock= PowerMockito.spy(new ClassToMock());
(6)@InjectMocks
一般用于创建被测试类的实例,使用@Spy和@Mock创建的对象会注入到该实例中去。
@Mock注解和@Spy注解的区别:
(1)使用@Mock注解创建的对象所有的方法为空,默认的返回值为null
(2)使用@Spy注解创建的对象是真实的方法和真实的返回值,所以在设置函数的预期返回值时,如以下错误格式时,会先调用一次真实的方法,不符合我们的预期。
如果是@Mock对象,因为没有真实的方法,即使先执行一次也没有什么影响。
错误:PowerMockito.when(testclass,"privateMethod",Mockito.anyString()).thenReturn("SomeString");
正确:PowerMockito.doReturn("SomeString").when(testclass,"privateMethod",Mockito.anyString());
以下用powermock模拟私有函数来具体讲解@Mock和@Spy的区别。
3. PowerMock模拟私有函数
被测试类
public class PrivateMockClass {
public String method1(String param){
System.out.println(param);
return privateMethod(param);
}
private String privateMethod(String param){
String result = "Hi"+param;
System.out.println(result);
return result;
}}
测试类
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.junit.Assert.*;
@RunWith(PowerMockRunner.class)
@PrepareForTest({PrivateMockClass.class})
public class PrivateMockClassTest {
@Spy//使用@spy注解需要手动new对象
private PrivateMockClass testclass = new PrivateMockClass();
@Mock
private PrivateMockClass test;
//使用@spy注解进行测试
@Test
public void testMethod1() throws Exception{
//错误:PowerMockito.when(testclass,"privateMethod","private method").thenReturn("Hi private method");
PowerMockito.doReturn("Hi private method").when(testclass,"privateMethod",Mockito.anyString());
Assert.assertEquals("Hi private method",testclass.method1("123"));
}
//使用@Mock注解进行测试
@Test
public void testMethod()throws Exception {
PowerMockito.when(test,"privateMethod", Mockito.anyString()).thenReturn("Hi private method");
//需要调用一次真实的方法,否则test.method1()返回null
PowerMockito.when(test.method1(Mockito.anyString())).thenCallRealMethod();
Assert.assertEquals("Hi private method",test.method1("456"));
}
}
4. PowerMock模拟静态函数
被测试类
public class StaticMockClass {
public int method(int a){
return Ulity.staticMethod(a);
}
}
静态函数
public class Ulity {
public static int staticMethod(int a){
return a+a;
}
}
测试类
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.junit.Assert.*;
@RunWith(PowerMockRunner.class)
@PrepareForTest({Ulity.class})
public class StaticMockClassTest {
@Spy
private StaticMockClass testclass = new StaticMockClass();
@Test
public void method()throws Exception {
PowerMockito.mockStatic(Ulity.class);
PowerMockito.when(Ulity.staticMethod(Mockito.anyInt())).thenReturn(2);
assertEquals(2,testclass.method(111));
}
}
5. PowerMock模拟构造函数
被测试类,其中UserBean为一个实体类
public class ConstructorMockClass {
public UserBean method(){
UserBean user = new UserBean(1,"张三","男");
System.out.println("ID:"+user.getId()+"姓名:"+user.getName()+"性别:"+user.getSex());
return user;
}
}
测试类
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.junit.Assert.*;
@RunWith(PowerMockRunner.class)
@PrepareForTest({ConstructorMockClass.class})
public class ConstructorMockClassTest {
@Mock
private UserBean user ;
@InjectMocks
private ConstructorMockClass testclass = new ConstructorMockClass();
@Test
public void method() throws Exception{
//UserBean user = PowerMockito.mock(UserBean.class);
PowerMockito.whenNew(UserBean.class).withArguments(Mockito.anyInt(),Mockito.anyString(),Mockito.anyString()).thenReturn(user);
assertEquals(user,testclass.method());
}
}
6. PowerMock模拟final函数
与powermock模拟私有函数类似