java之UT

 

EasyMock介绍

一、 mock介绍

1.1简介

mock测试
就是在测试过程中,对于某些不容易构造或者 不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法。
mock对象
这个虚拟的对象就是mock对象。mock对象就是真实对象在调试期间的代替品。
mock对象使用范畴
真实对象具有不可确定的行为,产生不可预测的效果,(如:股票行情,天气预报) 真实对象很难被创建的 真实对象的某些行为很难被触发 真实对象实际上还不存在的(和其他开发小组或者和新的硬件打交道)等等.

什么时候需要Mock对象

----- 真实对象具有不可确定的行为(产生不可预测的结果,如股票的行情)
----- 真实对象很难被创建(比如具体的web容器)
----- 真实对象的某些行为很难触发(比如网络错误)
----- 真实情况令程序的运行速度很慢
----- 真实对象有用户界面
----- 测试需要询问真实对象它是如何被调用的(比如测试可能需要验证某个回调函数是否被调用了)
----- 真实对象实际上并不存在(当需要和其他开发小组,或者新的硬件系统打交道的时候,这是一个普遍的问题)

1.2举例说明

一个闹钟根据时间来进行提醒服务,如果过了下午5点钟就播放音频文件提醒大家下班了,如果我们要利用真实的对象来测试的话就只能苦苦等到下午五点,然后把耳朵放在音箱旁...我们可不想这么笨,我们应该利用 mock对象来进行测试,这样我们就可以模拟控制时间了,而不用苦苦等待时钟转到下午5点钟了。一个闹钟根据时间来进行提醒服务,如果过了下午5点钟就播 放音频文件提醒大家下班了,如果我们要利用真实的对象来测试的话就只能苦苦等到下午五点,然后把耳朵放在音箱旁...我们可不想这么笨,我们应该利用 mock对象来进行测试,这样我们就可以模拟控制时间了,而不用苦苦等待时钟转到下午5点钟了。


[java]  view plain copy
  1. public abstract class Environmental {  
  2.     boolean playedWav = false;  
  3.   
  4.     public abstract long getTime();  
  5.   
  6.     public abstract void playWavFile(String fileName);  
  7.   
  8.     public abstract boolean wavWasPlayed();  
  9.   
  10.     public abstract void resetWav();  
  11. }  

 真实的实现代码:

[java]  view plain copy
  1. public class SystemEnvironment extends Environmental {  
  2.     public long getTime() {  
  3.         return System.currentTimeMillis();  
  4.     }  
  5.   
  6.     public void playWavFile(String fileName) {  
  7.         playedWav = true;  
  8.     }  
  9.   
  10.     public boolean wavWasPlayed() {  
  11.         return playedWav;  
  12.     }  
  13.   
  14.     public void resetWav() {  
  15.         playedWav = false;  
  16.     }  
  17. }  

下面是mock对象:

[java]  view plain copy
  1. public class MockSystemEnvironment extends Environmental {  
  2.     private long currentTime;  
  3.   
  4.     public long getTime() {  
  5.         return currentTime;  
  6.     }  
  7.   
  8.     public void setTime(long currentTime) {  
  9.         this.currentTime = currentTime;  
  10.     }  
  11.   
  12.     public void playWavFile(String fileName) {  
  13.         playedWav = true;  
  14.     }  
  15.   
  16.     public boolean wavWasPlayed() {  
  17.         return playedWav;  
  18.     }  
  19.   
  20.     public void resetWav() {  
  21.         playedWav = false;  
  22.     }  
  23. }  

  下面是一个调用getTime的具体类:

[java]  view plain copy
  1. public class Checker {  
  2.     private Environmental env;  
  3.   
  4.     public Checker(Environmental env) {  
  5.         this.env = env;  
  6.     }  
  7.   
  8.     public void reminder() {  
  9.         Calendar cal = Calendar.getInstance();  
  10.         cal.setTimeInMillis(env.getTime());  
  11.         int hour = cal.get(Calendar.HOUR_OF_DAY);  
  12.         if (hour >= 17) {  
  13.             env.playWavFile("quit_whistle.wav");  
  14.         }  
  15.     }  
  16. }  

使用env.getTime()的被测代码并不知道测试环境和真实环境之间的区别,因为它们都实现了相同的接口。现在,你可以借助mock对象,通过把时间设置为已知值,并检查行为是否如预期那样来编写测试。

[java]  view plain copy
  1. public class TestChecker extends TestCase {  
  2.     public void testQuittingTime() {  
  3.         MockSystemEnvironment env = new MockSystemEnvironment();  
  4.         Calendar cal = Calendar.getInstance();  
  5.         cal.set(Calendar.YEAR, 2006);  
  6.         cal.set(Calendar.MONTH, 11);  
  7.         cal.set(Calendar.DAY_OF_MONTH, 7);  
  8.         cal.set(Calendar.HOUR_OF_DAY, 16);  
  9.         cal.set(Calendar.MINUTE, 55);  
  10.                   
  11.         //设置时间为16:55          
  12.         long t1 = cal.getTimeInMillis();  
  13.         System.out.println(t1);  
  14.         env.setTime(t1);  
  15.         Checker checker = new Checker(env);  
  16.         checker.reminder();  
  17.         assertFalse(env.wavWasPlayed());  
  18.           
  19.         //设置时间为17:00  
  20.         t1 += (5 * 60 * 1000);  
  21.         System.out.println(t1);  
  22.         env.setTime(t1);  
  23.         checker.reminder();  
  24.         assertTrue(env.wavWasPlayed());  
  25.         env.resetWav();  
  26.           
  27.         //设置时间为19:00  
  28.         t1 += 2 * 60 * 60 * 1000;  
  29.         System.out.println(t1);  
  30.         env.setTime(t1);  
  31.         checker.reminder();  
  32.         assertTrue(env.wavWasPlayed());  
  33.     }  
  34. }  

这就是mock对象的全部:伪装出真实世界的某些行为,使你可以集中精力测试好自己的代码。

1.1Mock工具介绍

如果每次都像上面那样自己写具体的mock对象,问题虽然解决了,但是好像有一些麻烦。
已经有一些第三方现成的mock对象供我们使用了。
在Java阵营中主要的Mock测试工具有 JMock,MockCreator,Mockrunner,EasyMock,MockMaker等,在微软的.Net阵营中主要是 Nmock,.NetMock等。

一、 EasyMock介绍

2.1 简介

EasyMock是一种模拟测试的框架,用他来辅助模拟测试。当在测试过程中一些复杂的对象生成相当麻烦、费时或者根本无法生成时,可以用模拟的对象来代替真实的对象。
EasyMock 可以mock interface和java 类,但是class mocking是有一些限制的,
1) 不能mock类的 final方法 
如果final方法被调用,则只能执行原有的正常代码。 
2) 不能mock类的static 方法。 
同样如果private方法被调用,只能执行原有的正常代码。 
3) 不能mock类的一些特殊方法: equals(),toString()和hashCode().
原因是easymock在实现是为每个class mock对象提供了内建的以上三个方法。需要强调的是,对于基于interface的mock,这个限制也是同样存在的,即使以上三个方式是interface定义的一部分。
在使用时需要避开这种场景,或者组合使用其他的mock 框架比如jmockit来mock private方法和final方法 
4) 3.0版本之前 
org.easymock.classextension.EasyMock 被用来mock抽象类(abstract)和具体类 
org.easymock.EasyMock被用来mock接口(interface)
3.0版本之后
easymock class extension的class mocking功能已经无缝集成到easymock中,因此代码的编写简洁了很多。
现新版本是3.2

2.2 EasyMock的安装

EasyMock 是采用 MIT license的一个开源项目,您可以http://www.easymock.org/Downloads.html上下载到相关的 zip 文件。
如果使用 Eclipse 作为 IDE,把 easymock.jar 添加到项目的 Libraries 里就可以使用了(如下图所示)。此外,由于我们的测试用例运行在 JUnit 环境中,因此您还需要 JUnit.jar(版本3.8.1以上)。
步骤:
解压EasyMock zip文件(easymock.zip).
添加EasyMock jar 文件(easymock.jar) 到你的工程路径.
为了运行mock程序,也需要添加 Objenesis 、Cglib 和 asm到你的工程路径.
图1:Eclipse 项目中的 Libraries

2.3 record-replay-verify模型介绍

record-replay-verify 模型容许记录mock对象上的操作然后重演并验证这些操作。这是目前mock框架领域最常见的模型,几乎所有的mock框架都是用这个模型,有些是现实使用如easymock,有些是隐式使用如jmockit。
这个过程大致可以划分为以下几个步骤:
1)record 
使用 EasyMock 生成 Mock 对象; 
设定 Mock 对象的预期行为和输出; 
2)replay 
将 Mock 对象切换到 Replay 状态; 
3)verify 
调用 Mock 对象方法进行单元测试; 
对 Mock 对象的行为进行验证。

举例说明

[java]  view plain copy
  1. public interface MyTest {  
  2.     public boolean getBoolean();  
  3.     public int getInt(int i);  
  4.     public char getChar();  
  5.     public String getString();  
  6. }  

[java]  view plain copy
  1. public class MyTestTest {  
  2.   
  3.     @Test  
  4.     public void test() {  
  5.                 //使用 EasyMock 生成 Mock 对象;  
  6.         MyTest my=createMock(MyTest.class);               
  7.         //设定 Mock 对象的预期行为和输出  
  8.         expect(my.getBoolean()).andReturn(false);  
  9.         expect(my.getChar()).andReturn('b');          
  10.         expect(my.getString()).andReturn("world");  
  11.         expect(my.getInt(10)).andReturn(5);       
  12.         //将 Mock 对象切换到 Replay 状态  
  13.         replay(my);  
  14.         //调用 Mock 对象方法进行单元测试  
  15.         assertEquals(5, my.getInt(10));  
  16.         assertEquals(false, my.getBoolean());  
  17.         assertEquals('b', my.getChar());  
  18.         assertEquals("world", my.getString());  
  19.         //对 Mock 对象的行为进行验证  
  20.         verify(my);  
  21.     }  
  22. }  

三、EasyMock各部分详解

3.1 record部分

3.1.1 使用 EasyMock生成 Mock 对象

一些简单的测试用例只需要一个 Mock对象,这时,我们可以用以下的方法来创建 Mock对象:
MyTest  test1 = EasyMock.createMock(MyTest.class);
其中 createMock是 org.easymock.EasyMock类所提供的静态方法,你可以通过 static import将其引入(注:static import是 java 5.0 所提供的新特性)。
如果需要在相对复杂的测试用例中使用多个 Mock对象,EasyMock提供了另外一种生成和管理 Mock对象的机制:
EasyMock 类的 createControl方法能创建一个接口 IMocksControl的对象,该对象能创建并管理多个 Mock对象。如果需要在测试中使用多个 Mock对象,我们推荐您使用这一机制,因为它在多个 Mock对象的管理上提供了相对便捷的方法。

[java]  view plain copy
  1. public interface Test1 {  
  2.     public String getString();  
  3. }  
[java]  view plain copy
  1. public interface Test2 {  
  2.     public int getInt();  
  3. }  
[java]  view plain copy
  1. public class TestMock {  
  2.     //使用 IMocksControl创建并管理多个 Mock 对象。  
  3.     IMocksControl im=createControl();  
  4.     Test1 t1=im.createMock(Test1.class);  
  5.     Test2 t2=im.createMock(Test2.class);  
  6.     @Test  
  7.     public void test() {  
  8.         expect(t1.getString()).andReturn("hi");  
  9.         expect(t2.getInt()).andReturn(2);  
  10.           
  11.         im.replay();  
  12.           
  13.         assertEquals(2, t2.getInt());  
  14.         assertEquals("hi", t1.getString());  
  15.           
  16.         im.verify();  
  17.     }  
  18. }  

3.1.2  设定 Mock对象的预期行为和输出

Mock 对象的行为可以简单的理解为 Mock对象方法的调用和方法调用所产生的输出。在 EasyMock中,对 Mock对象行为的添加和设置是通过接口 IExpectationSetters来实现的。
IExpectationSetters<T> expect(final Tvalue);
IExpectationSetters<T> expectLastCall();

1)    IExpectationSetters<T>expect(final T value);

对于被mock的方法参数value,EasyMock 提供了灵活的参数匹配方式。
(1) 基于基本类型的比较
 eq(X value)
当实际值和预期值相同时匹配。适用于所有的简单类型和对象。
eq(X value, X delta)
当实际值在以value为基础以delta为区间的范围内匹配。适用于float和double。
anyBoolean(), anyByte(), anyChar(), anyDouble(), anyFloat(), anyInt(),anyLong(), anyObject(), anyShort()
匹配任意值。适用于所有的简单类型和对象。
aryEq(X value)
当通过Arrays.equals()比较返回true时匹配。适用于所有的简单类型和对象。
 这个是eq(X value)方法的数组版本,要求比较的两个数组拥有相同的长度,然后每个元素都"相同",即都可以满足eq(X value)方法。
lt(X value), leq(X value), geq(X value), gt(X value)
当实际值小于、小于等于、大于等于、大于预期值时匹配。适用于所有数值简单类型。
(2) 基于对象的比较
eq(X value)
当实际值和预期值相同时匹配。和基本类型类似,不过对于Object,是通过调用equals()方法来进行比较。
same(X value)
当实际值和预期值是同一个对象引用时匹配。适用于对象。  和eq()不同,same()是通过比较对象引用来进行比较的。类似java代码中, a.equals(b)和a == b的差别。
anyObject() 和 anyObject(Class<T> clazz)
 类似基本类型的any***()方法,非常宽松,在我们不介意参数值时使用。
isA(Class clazz)
匹配当前类或其子类的实例。适用于对象。  和anyObject(Class<T>clazz) 非常,唯一一个差别在于当输入参数为null时,anyObject(Class<T>clazz)返回true而isA(Class<T>clazz) 返回false。
(3) 逻辑计算
and(X first, X second)
当两个匹配器同时匹配时匹配。适用于所有的简单类型和对象。
or(X first, X second)
当两个匹配器有任何一个匹配时匹配。适用于所有的简单类型和对象。
not(X value)
当指定的匹配器不匹配时匹配。
 此外在参数匹配中,有几个特殊角色,享受的待遇与众不同,easymock为它们提供了专有方法。
1. Comparable
对于实现了Comparable接口的对象,easymock提供了一系列的专用方法来处理,包括eq, gt, lt, geq, leq:
cmpEq(Comparable<T> value) gt(Comparable<T> value)lt(Comparable<T> value) geq(Comparable<T> value)leq(Comparable<T> value)
这个特殊处理非常合理,本来Comparable接口就提供了比较的功能,在参数匹配时应该容许直接使用。
2. string
由于字符串匹配使用的场景非常多,因此easymock为此也提供了几个常见的参数匹配方法:
contains(String substring) startsWith(String prefix) endsWith(String suffix)contains/startsWith/endsWith是简单的字符串查找,当实际值开始、中间、或结尾处含有期望值时匹配。适用于String类型。
matches(String regex)
find(String regex)
则通过支持正则表达式来提供复杂匹配。
3. null
isNull()
当实际值是null时匹配。适用于对象。
notNull()
当实际值不为null时匹配。适用于对象。
 对于Object匹配,很常见的一个场景就是输入的参数为null,easymock中提供isNull()和 notNull() 两个方法来完成对null值的匹配。
 开发中,经常会遇到下面这种场景,期望输入的参数满足isA()或者容许为null。而直接使用isA(),是不能支持null的,即如果参数为null时isA()会报不匹配。这个不是easymock的bug,而是刻意而为,解决的方法是使用 or(isA(...), isNull(...))或者anyObject()。

举例说明

[java]  view plain copy
  1. public interface MyTest {  
  2.     public int getInt(int i);  
  3.     public int getInt(int[] i);  
  4.     public int getInt(Object obj);  
  5.     public double getDouble(double d);  
  6.     public boolean getBoolean(long l);  
  7.       
  8. }  
  9. public class MyTestTest {  
  10.     Father fa=new Father();  
  11.     Son son=new Son();  
  12.     Son son2=null;  
  13.     @Test  
  14.     public void test() {  
  15.         MyTest my=createMock(MyTest.class);  
  16.         int[] a={1,2,3,4,5};  
  17.         int[] b={1,2,3,4,5,6};  
  18.         int[] c={1,2,3,6,5};  
  19.         int[] d={1,2,3,4,5};  
  20.         //record  
  21.         /** eq(X value) 
  22.          * 当实际值和预期值相同时匹配。适用于所有的简单类型和对象。 
  23.          */  
  24.         expect(my.getInt(eq(10))).andReturn(10);  
  25.           
  26.         /** eq(X value, X delta) 
  27.          * 当实际值在以value为基础以delta为区间的范围内匹配。适用于float和double。 
  28.          */  
  29.         expect(my.getDouble(eq(102))).andReturn(5.0);  
  30.           
  31.         /** anyBoolean(), anyByte(), anyChar(), anyDouble(), anyFloat(), anyInt(), anyLong(), anyObject(), anyShort() 
  32.          * 匹配任意值。适用于所有的简单类型和对象。 
  33.          */  
  34.         expect(my.getBoolean(anyLong())).andReturn(true);  
  35.           
  36.         /** aryEq(X value) 
  37.          * 当通过Arrays.equals()比较返回true时匹配。适用于所有的简单类型和对象。 
  38.          */  
  39.         expect(my.getInt(aryEq(a))).andReturn(100);  
  40.           
  41.         /** lt(X value), leq(X value), geq(X value), gt(X value) 
  42.          * Lt=less than 
  43.          * Leq=less or equal 
  44.          * Geq=greter or equal 
  45.          * Gt=greater than 
  46.          * 当实际值小于、小于等于、大于等于、大于预期值时匹配。适用于所有数值简单类型。 
  47.          */  
  48.         expect(my.getInt(lt(20))).andReturn(1);  
  49.         //expect(my.getInt(eq(20))).andReturn(5);  
  50.         expect(my.getInt(leq(20))).andReturn(2);  
  51.         expect(my.getInt(geq(20))).andReturn(3);  
  52.         expect(my.getInt(gt(20))).andReturn(4);  
  53.         expect(my.getInt(eq(20))).andReturn(5);  
  54.           
  55.         /** isA(Class clazz) 
  56.          * 匹配当前类或其子类的实例。适用于对象. 
  57.          * 和anyObject(Class<T> clazz) 非常,唯一一个差别在于当输入参数为null时, 
  58.          * anyObject(Class<T> clazz)返回true而isA(Class<T> clazz) 返回false。 
  59.          */  
  60.         expect(my.getInt(anyObject(Father.class))).andReturn(1000);  
  61.         expect(my.getInt(isA(Father.class))).andReturn(1001);  
  62.         /** 
  63.          * and(X first, X second) 
  64.          * 当两个匹配器同时匹配时匹配。适用于所有的简单类型和对象。 
  65.          * or(X first, X second) 
  66.          * 当两个匹配器有任何一个匹配时匹配。适用于所有的简单类型和对象。 
  67.          * not(X value) 
  68.          * 当指定的匹配器不匹配时匹配。 
  69.          */  
  70.         expect(my.getInt(and(lt(5), gt(1)))).andReturn(200);   
  71.         //replay  
  72.         replay(my);  
  73.         //verify  
  74.         assertEquals(10, my.getInt(10));      
  75.         assertEquals(5.0,my.getDouble(11),0);  
  76.         assertEquals(true, my.getBoolean(25));  
  77.           
  78.         //assertEquals(100, my.getInt(b));  
  79.         //assertEquals(100, my.getInt(c));  
  80.         assertEquals(100, my.getInt(d));  
  81.           
  82.         assertEquals(1, my.getInt(19));   
  83.         assertEquals(2, my.getInt(20));   
  84.         assertEquals(3, my.getInt(20));   
  85.         assertEquals(4, my.getInt(21));  
  86.         assertEquals(5, my.getInt(20));  
  87.           
  88.         assertEquals(1000, my.getInt(son2));  
  89.         //assertEquals(1001, my.getInt(son2));  
  90.         assertEquals(1001, my.getInt(son));  
  91.           
  92.         assertEquals(200, my.getInt(4));  
  93.           
  94.         verify(my);  
  95.     }  
  96.   
  97. }  

2)IExpectationSetters<T> expectLastCall();
如果mock对象的方法是void,则需要使用expectLastCall() 

[java]  view plain copy
  1. public interface Test1 {  
  2.     public void method1() throws IOException;  
  3. }  
  4. public class Test2 {  
  5.       
  6.     public int runTest1(Test1 t1) throws IOException{  
  7.         try{  
  8.             t1.method1();             
  9.             return 1;  
  10.         }catch(IOException e){  
  11.             return -1;        
  12.         }  
  13.     }  
  14. }  
  15. public class Test2Mock {  
  16.     Test2 t2=new Test2();  
  17.     Test1 t1=EasyMock.createMock(Test1.class);  
  18.     @Test  
  19.     public void test() throws IOException {  
  20.         //无返回值的mock测试举例  
  21.         t1.method1();  
  22.         EasyMock.expectLastCall();        
  23.         EasyMock.replay(t1);          
  24.         int a=t2.runTest1(t1);  
  25.         assertEquals(1, a);       
  26.         EasyMock.verify(t1);  
  27.           
  28.     }  
  29.   
  30. }  

3.1.3 设定输出

Mock 对象方法的调用可能产生两种类型的输出:(1)产生返回值;(2)抛出异常
接口 IExpectationSetters 提供了多种设定预期输出的方法

1)设定预期返回值

接口IExpectationSetters 和设定返回值相对应的是 andReturn 方法:
IExpectationSetters<T> andReturn(T value);
如:
expect(my.getInt(eq(10))).andReturn(10);

有时,我们希望某个方法的调用总是返回一个相同的值,为了避免每次调用都为 Mock 对象的行为进行一次设定,我们可以用设置默认返回值的方法:
void andStubReturn(Object value);


[java]  view plain copy
  1. public class MyTest {  
  2.   
  3.     public int getInt(int i) {  
  4.         return 1;  
  5.     }  
  6.   
  7. }  
  8. public class MyTestTest {  
  9.   
  10.     @Test  
  11.     public void test() {  
  12.         MyTest my=createMock(MyTest.class);  
  13.           
  14.         //设置默认  
  15.         expect(my.getInt(10)).andReturn(5);       
  16.         expect(my.getInt(anyInt())).andStubReturn(1);  
  17.           
  18.         replay(my);  
  19.           
  20.         //默认值检验  
  21.         assertEquals(5, my.getInt(10));  
  22.         assertEquals(1, my.getInt(3));  
  23.           
  24.         verify(my);  
  25.     }  
  26.   
  27. }  

2)设定预期异常抛出

对象行为的预期输出除了可能是返回值外,还有可能是抛出异常。IExpectationSetters提供了设定预期抛出异常的方法:
IExpectationSetters<T> andThrow(Throwable throwable); 和设定默认返回值类似,IExpectationSetters 接口也提供了设定抛出默认异常的函数:
void andStubThrow(Throwable throwable);
非受检异常(也就是:RuntimeException,Error和它们的子类)能够在任何方法中被抛出。
受检异常只能在显示声明它们会被抛出的方法中被抛出。


[java]  view plain copy
  1. public interface Test1 {  
  2.     public void method1() throws IOException;  
  3. }  
  4. public class Test2 {  
  5.       
  6.     public int runTest1(Test1 t1) throws IOException{  
  7.         try{  
  8.             t1.method1();             
  9.             return 1;  
  10.         }catch(IOException e){  
  11.             return -1;        
  12.         }  
  13.     }  
  14. }  
  15. public class Test2Mock {  
  16.     Test2 t2=new Test2();  
  17.     Test1 t1=EasyMock.createMock(Test1.class);  
  18.     @Test  
  19.     public void test() throws IOException {  
  20.         //无返回值的mock测试举例  
  21.         t1.method1();  
  22.         EasyMock.expectLastCall();        
  23.         EasyMock.replay(t1);          
  24.         int a=t2.runTest1(t1);  
  25.         assertEquals(1, a);       
  26.         EasyMock.verify(t1);  
  27.           
  28.         //返回异常的mock举例  
  29.         EasyMock.reset(t1);  
  30.         t1.method1();  
  31.         EasyMock.expectLastCall().andThrow(new IOException());  
  32.         EasyMock.replay(t1);          
  33.         int b=t2.runTest1(t1);  
  34.         assertEquals(-1, b);          
  35.         EasyMock.verify(t1);  
  36.           
  37.     }  
  38.   
  39. }  

3.1.4 设定预期方法调用次数

除了对预期输出进行设定,IExpectationSetters接口还允许用户对方法的调用次数作出限制。在 IExpectationSetters 所提供的这一类方法中,常用的一种是 times方法:
IExpectationSetters<T>times(int count); 该方法可以 Mock对象方法的调用次数进行确切的设定。假设我们希望 mockResultSet 的 getString 方法在测试过程中被调用3次,期间的返回值都是 "My return value",我们可以用如下语句:
mockResultSet.getString(1);expectLastCall().andReturn("My return value").times(3);注意到 andReturn和andThrow 方法的返回值依然是一个 IExpectationSetters 实例,因此我们可以在此基础上继续调用 times 方法。
除了设定确定的调用次数,IExpectationSetters还提供了另外几种设定非准确调用次数的方法: times(int minTimes, int maxTimes):该方法最少被调用 minTimes 次,最多被调用 maxTimes 次。 atLeastOnce():该方法至少被调用一次。 anyTimes():该方法可以被调用任意次。
某些方法的返回值类型是 void,对于这一类方法,我们无需设定返回值,只要设置调用次数就可以了。以 ResultSet 接口的 close 方法为例,假设在测试过程中,该方法被调用3至5次:
mockResultSet.close(); expectLastCall().times(3,5); 为了简化书写,EasyMock还提供了另一种设定 Mock 对象行为的语句模式。对于上例,您还可以将它写成:
expect(mockResult.close()).times(3, 5);

举例:

[java]  view plain copy
  1. public interface MyTest {  
  2.     public int getInt(int i);  
  3. }  
  4. public class MyTestTime {  
  5.   
  6.     @Test  
  7.     public void test() {  
  8.         MyTest my=createMock(MyTest.class);  
  9.           
  10.         //record  
  11.         expect(my.getInt(10)).andReturn(2).times(2);  
  12.         expect(my.getInt(10)).andReturn(1).once();  
  13.         expect(my.getInt(10)).andReturn(4).times(3,5);  
  14.         /** 不要在浮动次数后面再添加新的期望输出,会报出 
  15.          *  "last method called on mock already has a non-fixed count set" 
  16.          *  的IllegalStateException  
  17.          */       
  18. //      expect(my.getInt(10)).andReturn(1);  
  19. //      expect(my.getInt(10)).andReturn(4).atLeastOnce();  
  20. //      expect(my.getInt(10)).andReturn(1).anyTimes();  
  21.           
  22.         //replay  
  23.         replay(my);  
  24.           
  25.         //verify  
  26.         assertEquals(2, my.getInt(10));  
  27.         assertEquals(2, my.getInt(10));  
  28.         assertEquals(1, my.getInt(10));  
  29.         assertEquals(4, my.getInt(10));  
  30.         assertEquals(4, my.getInt(10));  
  31.         assertEquals(4, my.getInt(10));   
  32.         assertEquals(4, my.getInt(10));   
  33.         assertEquals(4, my.getInt(10));   
  34.         assertEquals(1, my.getInt(10));   
  35.         assertEquals(4, my.getInt(10));   
  36.         verify(my);  
  37.     }  
  38.   
  39. }  

3.1.5 改变一个方法调用的行为

方法的调用次数、andReturn和andThrow 可以串联调用。
举例:

[java]  view plain copy
  1. public interface MyTest {  
  2.     public int getInt(int i);  
  3. }  
  4. public class MyTestTime {  
  5.   
  6.     @Test  
  7.     public void test() {  
  8.         MyTest my=createMock(MyTest.class);  
  9.           
  10.         //方法的调用次数、andReturn和andThrow 可以串联调用  
  11.         //expect(my.getInt(10)).andReturn(2).times(2).andReturn(1).once().andReturn(4).times(3,5);  
  12.           
  13.         //replay  
  14.         replay(my);  
  15.           
  16.         //verify  
  17.         assertEquals(2, my.getInt(10));  
  18.         assertEquals(2, my.getInt(10));  
  19.         assertEquals(1, my.getInt(10));  
  20.         assertEquals(4, my.getInt(10));  
  21.         assertEquals(4, my.getInt(10));  
  22.         assertEquals(4, my.getInt(10));   
  23.         assertEquals(4, my.getInt(10));   
  24.         assertEquals(4, my.getInt(10));   
  25.         assertEquals(1, my.getInt(10));   
  26.         assertEquals(4, my.getInt(10));   
  27.         verify(my);  
  28.     }  
  29.   
  30. }  

3.2 Replay部分

在生成 Mock 对象和设定Mock 对象行为两个阶段,Mock 对象的状态都是Record 。在这个阶段,Mock 对象会记录用户对预期行为和输出的设定。
在使用 Mock 对象进行实际的测试前,我们需要将 Mock 对象的状态切换为 Replay。在 Replay 状态,Mock对象能够根据设定对特定的方法调用作出预期的响应。
将 Mock 对象切换成 Replay 状态有两种方式,您需要根据 Mock 对象的生成方式进行选择。如果 Mock 对象是通过 org.easymock.EasyMock 类提供的静态方法 createMock 生成的(第1节中介绍的第一种 Mock 对象生成方法),那么EasyMock 类提供了相应的 replay 方法用于将 Mock 对象切换为 Replay 状态:
replay(mockResultSet); 
如果 Mock 对象是通过 IMocksControl 接口提供的 createMock 方法生成的(第1节中介绍的第二种Mock对象生成方法),那么您依旧可以通过 IMocksControl 接口对它所创建的所有 Mock 对象进行切换:
control.replay();

3.3 Verify部分

在利用 Mock 对象进行实际的测试过程之后,我们还有一件事情没有做:对 Mock 对象的方法调用的次数进行验证。
为了验证指定的方法调用真的完成了,我们需要调用 verify 方法进行验证。如果Mock对象的方法没有被调用过,将会得到下面的异常:
java.lang.AssertionError:   Expectation failure onverify:
和 replay 方法类似,您需要根据 Mock 对象的生成方式来选用不同的验证方式。如果 Mock 对象是由 org.easymock.EasyMock 类提供的 createMock 静态方法生成的,那么我们同样采用EasyMock 类的静态方法 verify 进行验证:
verify(mockResultSet); 如果Mock对象是有 IMocksControl 接口所提供的 createMock 方法生成的,那么采用该接口提供的 verify 方法,例如第1节中的IMocksControl实例 control:
control.verify();

3.4 对象重用

为了避免生成过多的 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 状态。

[java]  view plain copy
  1. public interfaceMyTest {  
  2.   
  3.     public int getInt(int i);  
  4. }  
  5. public class MyTestTest {  
  6.   
  7.     @Test  
  8.     public void test() {  
  9.         MyTest my=createMock(MyTest.class);  
  10.           
  11.         //设置默认  
  12.         expect(my.getInt(10)).andReturn(5);       
  13.         expect(my.getInt(anyInt())).andStubReturn(1);  
  14.           
  15.         replay(my);  
  16.           
  17.         //默认值检验  
  18.         assertEquals(5, my.getInt(10));  
  19.         assertEquals(1, my.getInt(3));  
  20.           
  21.         verify(my);  
  22.           
  23.         /* 为了避免生成过多的 Mock 对象,EasyMock 允许对原有 Mock 对象进行重用。 
  24.          * 重设所有值为1,这样getInt(10)=1 
  25.          */  
  26.         reset(my);        
  27.         expect(my.getInt(anyInt())).andStubReturn(1);         
  28.         replay(my);       
  29.         assertEquals(1, my.getInt(10));       
  30.         verify(my);  
  31.     }  
  32.   
  33. }  

3.5 特殊的 Mock 对象类型

到目前为止,我们所创建的 Mock 对象都属于 EasyMock 默认的 Mock 对象类型,它对预期方法的调用次序不敏感,对非预期的方法调用抛出 AssertionError。除了这种默认的 Mock 类型以外,EasyMock 还提供了一些特殊的 Mock 类型用于支持不同的需求。

Strick Mock 对象

如果 Mock 对象是通过EasyMock.createMock() 或是 IMocksControl.createMock() 所创建的,那么在进行 verify 验证时,方法的调用顺序是不进行检查的。如果要创建方法调用的先后次序敏感的Mock 对象(Strick Mock),应该使用EasyMock.createStrickMock()来创建

类似于 createMock,我们同样可以用 IMocksControl 实例来创建一个 Strick Mock 对象:

IMocksControl control =EasyMock.createStrictControl();

Nice Mock 对象

使用 createMock() 创建的 Mock 对象对非预期的方法调用默认的行为是抛出 AssertionError,如果需要一个默认返回0,null 或 false 等"无效值"的"Nice Mock" 对象,可以通过 EasyMock 类提供的 createNiceMock() 方法创建。类似的,你也可以用IMocksControl 实例来创建一个 Nice Mock 对象。

 

举例:

[java]  view plain copy
  1. public interface MyTest {  
  2.     public boolean getBoolean();  
  3.     public int getInt(int i);  
  4.     public char getChar();  
  5.     public String getString();  
  6. }  
  7. public class MyTestOrder {  
  8.   
  9.     @Test  
  10.     public void test() {  
  11.         MyTest my=createMock(MyTest.class);  
  12.         /** 
  13.          * 普通的mock方式默认不开启调用顺序检测。 意思就是说两个方法谁前谁后对结果没有影响。 
  14.          * 但同一个方法的两次预期受顺序影响 
  15.          */  
  16.         //record  
  17.         expect(my.getChar()).andReturn('b');          
  18.         expect(my.getInt(10)).andReturn(5);  
  19.         expect(my.getChar()).andReturn('c');  
  20.         //replay  
  21.         replay(my);  
  22.         //verify  
  23.         assertEquals(5, my.getInt(10));  
  24.         assertEquals('b', my.getChar());  
  25.         assertEquals('c', my.getChar());  
  26.         verify(my);  
  27.     }  
  28.   
  29. }  
  30. public class MyTestOrderStrictMock {  
  31.   
  32.     @Test  
  33.     public void test() {  
  34.         MyTest my=createStrictMock(MyTest.class);  
  35.         /** 
  36.          * 普通的mock方式默认不开启调用顺序检测。 意思就是说两个方法谁前谁后对结果没有影响。 
  37.          * 但同一个方法的两次预期受顺序影响 
  38.          */  
  39.         //record  
  40.         expect(my.getInt(10)).andReturn(5);  
  41.         expect(my.getChar()).andReturn('b');          
  42.         //expect(my.getInt(10)).andReturn(5);  
  43.         expect(my.getChar()).andReturn('c');  
  44.         //replay  
  45.         replay(my);  
  46.         //verify  
  47.         /** 
  48.          * expect(my.getChar()).andReturn('b');      
  49.          * expect(my.getInt(10)).andReturn(5); 
  50.          * assertEquals(5, my.getInt(10));       
  51.          * assertEquals('b', my.getChar()); 
  52.          * 上面的代码会产生: 
  53.          * java.ang.AssertionError:Unexpected method call  
  54.          */  
  55.         assertEquals(5, my.getInt(10));  
  56.         assertEquals('b', my.getChar());  
  57.         assertEquals('c', my.getChar());  
  58.         verify(my);  
  59.     }  
  60.   
  61. }  
  62. public class MyTestOrderNiceMock {  
  63.     @Test  
  64.     public void test() {  
  65.         MyTest my=createNiceMock(MyTest.class);  
  66.                   
  67.         //record  
  68.         /** 
  69.          * 调用到不期望的方法时不会使测试失败, 
  70.          * 如果原方法返回的类型是number的 它就会返回0, 
  71.          * 如果是boolean 它会返回false, 
  72.          * 如果是object它会返回null. 
  73.          */  
  74.         //expect(my.getBoolean()).andReturn(false);  
  75.         expect(my.getChar()).andReturn('b');          
  76.         expect(my.getString()).andReturn("world");  
  77.         expect(my.getInt(10)).andReturn(5);       
  78.         //replay  
  79.         replay(my);  
  80.         //verify  
  81.         assertEquals(5, my.getInt(10));  
  82.         //getBoolean()未被调用设定预期值,默认返回false  
  83.         assertEquals(true, my.getBoolean());  
  84.         assertEquals('b', my.getChar());  
  85.         assertEquals("world", my.getString());  
  86.           
  87.         verify(my);  
  88.     }  
  89. }  

3.6 用EasyMock测试我们最开始的clock程序

[java]  view plain copy
  1. public abstract class Environmental {  
  2.     boolean playedWav = false;  
  3.   
  4.     public abstract long getTime();  
  5.   
  6.     public abstract void playWavFile(String fileName);  
  7.   
  8.     public abstract boolean wavWasPlayed();  
  9.   
  10.     public abstract void resetWav();  
  11. }  

[java]  view plain copy
  1. public class SystemEnvironment extends Environmental {  
  2.     public long getTime() {  
  3.         return System.currentTimeMillis();  
  4.     }  
  5.   
  6.     public void playWavFile(String fileName) {  
  7.         playedWav = true;  
  8.     }  
  9.   
  10.     public boolean wavWasPlayed() {  
  11.         return playedWav;  
  12.     }  
  13.   
  14.     public void resetWav() {  
  15.         playedWav = false;  
  16.     }  
  17. }  
[java]  view plain copy
  1. public class Checker {  
  2.     private Environmental env;  
  3.   
  4.     public Checker(Environmental env) {  
  5.         this.env = env;  
  6.     }  
  7.   
  8.     public void reminder() {  
  9.         Calendar cal = Calendar.getInstance();  
  10.         cal.setTimeInMillis(env.getTime());  
  11.         int hour = cal.get(Calendar.HOUR_OF_DAY);  
  12.         if (hour >= 17) {  
  13.             env.playWavFile("quit_whistle.wav");  
  14.         }  
  15.     }  
  16. }  
[java]  view plain copy
  1. public class CheckerTest extends TestCase{  
  2.   
  3.     public void testQuittingTime() {  
  4.         /** 
  5.          * 有时候我们需要将这个测试类作为主要测试对象,我们希望这个类中的部分 
  6.          * (通常是大部分)方法保持原有的正常行为,只有个别方法被我们mock掉以便测试。 
  7.          */  
  8.         SystemEnvironment env = EasyMock.createMockBuilder(SystemEnvironment.class).addMockedMethod("getTime").createMock();  
  9.           
  10.         Calendar cal = Calendar.getInstance();  
  11.         cal.set(Calendar.YEAR, 2006);  
  12.         cal.set(Calendar.MONTH, 11);  
  13.         cal.set(Calendar.DAY_OF_MONTH, 7);  
  14.         cal.set(Calendar.HOUR_OF_DAY, 16);  
  15.         cal.set(Calendar.MINUTE, 55);  
  16.                   
  17.         //设置时间为16:55          
  18.         long t1 = cal.getTimeInMillis();  
  19.         //设置时间为17:00  
  20.         long t2=t1+(5 * 60 * 1000);  
  21.         //设置时间为19:00  
  22.         long t3=t2+ 2 * 60 * 60 * 1000;  
  23.         /**  
  24.          * 在easymock中,对于mock对象的同一个方法,可以为每一次的调用定制不同的行为。在record阶段 
  25.          * easymock会精确的记录我们录入的行为,基于每一次的方法调用。             
  26.          */  
  27.         EasyMock.expect(env.getTime()).andReturn(t1).andReturn(t2).andReturn(t3);  
  28.           
  29.         EasyMock.replay(env);  
  30.         Checker checker = new Checker(env);  
  31.         checker.reminder();  
  32.         assertFalse(env.wavWasPlayed());  
  33.           
  34.         //设置时间为17:00  
  35.         checker.reminder();  
  36.         assertTrue(env.wavWasPlayed());  
  37.         env.resetWav();  
  38.           
  39.         //设置时间为19:00  
  40.         t1 += 2 * 60 * 60 * 1000;  
  41.         checker.reminder();  
  42.         assertTrue(env.wavWasPlayed());  
  43.           
  44.         EasyMock.verify(env);  
  45.     }  
  46.   
  47. }  

四、EasyMock 的工作原理

EasyMock 是如何为一个特定的接口动态创建 Mock对象,并记录 Mock 对象预期行为的呢?其实,EasyMock 后台处理的主要原理是利用java.lang.reflect.Proxy 为指定的接口创建一个动态代理,这个动态代理,就是我们在编码中用到的 Mock 对象。EasyMock 还为这个动态代理提供了一个 InvocationHandler 接口的实现,这个实现类的主要功能就是将动态代理的预期行为记录在某个映射表中和在实际调用时从这个映射表中取出预期输出。

具体看链接部分: http://www.ibm.com/developerworks/cn/opensource/os-cn-easymock/  



一、为什么要使用Mock工具

      在做单元测试的时候,我们会发现我们要测试的方法会引用很多外部依赖的对象,比如:(发送邮件,网络通讯,远程服务, 文件系统等等)。 而我们没法控制这些外部依赖的对象,为了解决这个问题,我们就需要用到Mock工具来模拟这些外部依赖的对象,来完成单元测试。

      二、为什么要使用PowerMock

      现如今比较流行的Mock工具如jMock EasyMock 、Mockito都有一个共同的缺点:不能mock静态、final、私有方法等。而PowerMock能够完美的弥补以上三个Mock工具的不足。

      三、PowerMock简介

      PowerMock是一个扩展了其它如EasyMock等mock框架的、功能更加强大的框架。PowerMock使用一个自定义类加载器和字节码操作来模拟静态方法构造函数,final类和方法,私有方法去除静态初始化器等等。通过使用自定义的类加载器,简化采用的IDE或持续集成服务器不需要做任何改变。熟悉PowerMock支持的mock框架的开发人员会发现PowerMock很容易使用,因为对于静态方法和构造器来说,整个的期望API是一样的。PowerMock旨在用少量的方法和注解扩展现有的API来实现额外的功能。目前PowerMock支持EasyMock和Mockito。

      四、PowerMock入门    

      PowerMock有两个重要的注解:

      –@RunWith(PowerMockRunner.class)

      –@PrepareForTest( { YourClassWithEgStaticMethod.class })

      如果你的测试用例里没有使用注解@PrepareForTest,那么可以不用加注解@RunWith(PowerMockRunner.class),反之亦然。当你需要使用PowerMock强大功能(Mock静态、final、私有方法等)的时候,就需要加注解@PrepareForTest。

      五、PowerMock基本用法

      (1) 普通Mock: Mock参数传递的对象

      测试目标代码:

1 public boolean callArgumentInstance(File file) {
2  
3      return file.exists();
4  
5 }

     测试用例代码: 

01 @Test 
02 public void testCallArgumentInstance() {
03   
04     File file = PowerMockito.mock(File.class); 
05  
06     ClassUnderTest underTest = new ClassUnderTest();
07    
08     PowerMockito.when(file.exists()).thenReturn(true);
09   
10     Assert.assertTrue(underTest.callArgumentInstance(file)); 
11 }

      说明:普通Mock不需要加@RunWith和@PrepareForTest注解。

       (2)  Mock方法内部new出来的对象

       测试目标代码:

01 public class ClassUnderTest {
02  
03     public boolean callInternalInstance(String path) { 
04  
05         File file = new File(path); 
06  
07         return file.exists(); 
08  
09     
10 }

       测试用例代码:    

01 @RunWith(PowerMockRunner.class
02 public class TestClassUnderTest {
03  
04     @Test 
05     @PrepareForTest(ClassUnderTest.class
06     public void testCallInternalInstance() throws Exception { 
07  
08         File file = PowerMockito.mock(File.class); 
09  
10         ClassUnderTest underTest = new ClassUnderTest(); 
11  
12         PowerMockito.whenNew(File.class).withArguments("bbb").thenReturn(file); 
13          
14         PowerMockito.when(file.exists()).thenReturn(true); 
15  
16         Assert.assertTrue(underTest.callInternalInstance("bbb")); 
17     
18 }

      说明:当使用PowerMockito.whenNew方法时,必须加注解@PrepareForTest和@RunWith。注解@PrepareForTest里写的类是需要mock的new对象代码所在的类。

     (3) Mock普通对象的final方法

     测试目标代码:

1 public class ClassUnderTest {
2  
3     public boolean callFinalMethod(ClassDependency refer) { 
4  
5         return refer.isAlive(); 
6  
7     
8 }

01 public class ClassDependency {
02      
03     public final boolean isAlive() {
04  
05         // do something 
06  
07         return false
08  
09     
10 }

       测试用例代码:

01 @RunWith(PowerMockRunner.class
02 public class TestClassUnderTest {
03  
04     @Test 
05     @PrepareForTest(ClassDependency.class
06     public void testCallFinalMethod() {
07  
08         ClassDependency depencency =  PowerMockito.mock(ClassDependency.class);
09   
10         ClassUnderTest underTest = new ClassUnderTest();
11   
12         PowerMockito.when(depencency.isAlive()).thenReturn(true);
13   
14         Assert.assertTrue(underTest.callFinalMethod(depencency));
15   
16     }
17 }

      说明: 当需要mock final方法的时候,必须加注解@PrepareForTest和@RunWith。注解@PrepareForTest里写的类是final方法所在的类。 

      (4) Mock普通类的静态方法

      测试目标代码:

1 public class ClassUnderTest {
2  
3     public boolean callStaticMethod() {
4   
5         return ClassDependency.isExist(); 
6  
7     }  
8 }

01 public class ClassDependency {
02     
03     public static boolean isExist() {
04  
05         // do something 
06  
07         return false
08  
09     
10 }

      测试用例代码:

01 @RunWith(PowerMockRunner.class
02 public class TestClassUnderTest {
03  
04     @Test 
05     @PrepareForTest(ClassDependency.class
06     public void testCallStaticMethod() {
07   
08         ClassUnderTest underTest = new ClassUnderTest();
09   
10         PowerMockito.mockStatic(ClassDependency.class); 
11  
12         PowerMockito.when(ClassDependency.isExist()).thenReturn(true);
13   
14         Assert.assertTrue(underTest.callStaticMethod());
15   
16     }
17 }

      说明:当需要mock静态方法的时候,必须加注解@PrepareForTest和@RunWith。注解@PrepareForTest里写的类是静态方法所在的类。

      (5) Mock 私有方法

      测试目标代码: 

01 public class ClassUnderTest {
02  
03     public boolean callPrivateMethod() { 
04  
05         return isExist(); 
06  
07     }       
08  
09     private boolean isExist() {
10    
11         return false
12  
13     }
14 }

     测试用例代码:  

01 @RunWith(PowerMockRunner.class
02 public class TestClassUnderTest {
03  
04     @Test 
05     @PrepareForTest(ClassUnderTest.class
06     public void testCallPrivateMethod() throws Exception { 
07  
08        ClassUnderTest underTest = PowerMockito.mock(ClassUnderTest.class); 
09  
10        PowerMockito.when(underTest.callPrivateMethod()).thenCallRealMethod(); 
11  
12        PowerMockito.when(underTest, "isExist").thenReturn(true);
13    
14        Assert.assertTrue(underTest.callPrivateMethod());
15   
16     }
17 }

       说明:和Mock普通方法一样,只是需要加注解@PrepareForTest(ClassUnderTest.class),注解里写的类是私有方法所在的类。 

       (6) Mock系统类的静态和final方法 

        测试目标代码:   

01 public class ClassUnderTest {
02  
03     public boolean callSystemFinalMethod(String str) {
04  
05         return str.isEmpty(); 
06  
07     
08  
09     public String callSystemStaticMethod(String str) {
10   
11         return System.getProperty(str); 
12  
13     }
14 }

      测试用例代码:

01 @RunWith(PowerMockRunner.class
02 public class TestClassUnderTest {
03  
04   @Test 
05   @PrepareForTest(ClassUnderTest.class
06   public void testCallSystemStaticMethod() { 
07  
08       ClassUnderTest underTest = new ClassUnderTest(); 
09  
10       PowerMockito.mockStatic(System.class); 
11  
12       PowerMockito.when(System.getProperty("aaa")).thenReturn("bbb");
13    
14       Assert.assertEquals("bbb", underTest.callJDKStaticMethod("aaa")); 
15  
16   
17 }

      说明:和Mock普通对象的静态方法、final方法一样,只不过注解@PrepareForTest里写的类不一样 ,注解里写的类是需要调用系统方法所在的类。

      六 、无所不能的PowerMock

       (1) 验证静态方法:

       PowerMockito.verifyStatic();
       Static.firstStaticMethod(param);

       (2) 扩展验证:

       PowerMockito.verifyStatic(Mockito.times(2)); //  被调用2次                                Static.thirdStaticMethod(Mockito.anyInt()); // 以任何整数值被调用

       (3) 更多的Mock方法

       http://code.google.com/p/powermock/wiki/MockitoUsage13

      七、PowerMock简单实现原理

       •  当某个测试方法被注解@PrepareForTest标注以后,在运行测试用例时,会创建一个新的org.powermock.core.classloader.MockClassLoader实例,然后加载该测试用例使用到的类(系统类除外)。

       •   PowerMock会根据你的mock要求,去修改写在注解@PrepareForTest里的class文件(当前测试类会自动加入注解中),以满足特殊的mock需求。例如:去除final方法的final标识,在静态方法的最前面加入自己的虚拟实现等。

       •   如果需要mock的是系统类的final方法和静态方法,PowerMock不会直接修改系统类的class文件,而是修改调用系统类的class文件,以满足mock需求。





  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值