一、 mock介绍
1.1简介
mock测试
就是在测试过程中,对于某些不容易构造或者 不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法。
mock对象
这个虚拟的对象就是mock对象。mock对象就是真实对象在调试期间的代替品。
mock对象使用范畴
真实对象具有不可确定的行为,产生不可预测的效果,(如:股票行情,天气预报) 真实对象很难被创建的 真实对象的某些行为很难被触发 真实对象实际上还不存在的(和其他开发小组或者和新的硬件打交道)等等.
什么时候需要Mock对象
----- 真实对象具有不可确定的行为(产生不可预测的结果,如股票的行情)
----- 真实对象很难被创建(比如具体的web容器)
----- 真实对象的某些行为很难触发(比如网络错误)
----- 真实情况令程序的运行速度很慢
----- 真实对象有用户界面
----- 测试需要询问真实对象它是如何被调用的(比如测试可能需要验证某个回调函数是否被调用了)
----- 真实对象实际上并不存在(当需要和其他开发小组,或者新的硬件系统打交道的时候,这是一个普遍的问题)
1.2举例说明
一个闹钟根据时间来进行提醒服务,如果过了下午5点钟就播放音频文件提醒大家下班了,如果我们要利用真实的对象来测试的话就只能苦苦等到下午五点,然后把耳朵放在音箱旁...我们可不想这么笨,我们应该利用 mock对象来进行测试,这样我们就可以模拟控制时间了,而不用苦苦等待时钟转到下午5点钟了。一个闹钟根据时间来进行提醒服务,如果过了下午5点钟就播 放音频文件提醒大家下班了,如果我们要利用真实的对象来测试的话就只能苦苦等到下午五点,然后把耳朵放在音箱旁...我们可不想这么笨,我们应该利用 mock对象来进行测试,这样我们就可以模拟控制时间了,而不用苦苦等待时钟转到下午5点钟了。
public abstract class Environmental {
boolean playedWav = false;
public abstract long getTime();
public abstract void playWavFile(String fileName);
public abstract boolean wavWasPlayed();
public abstract void resetWav();
}
真实的实现代码:
public class SystemEnvironment extends Environmental {
public long getTime() {
return System.currentTimeMillis();
}
public void playWavFile(String fileName) {
playedWav = true;
}
public boolean wavWasPlayed() {
return playedWav;
}
public void resetWav() {
playedWav = false;
}
}
下面是mock对象:
public class MockSystemEnvironment extends Environmental {
private long currentTime;
public long getTime() {
return currentTime;
}
public void setTime(long currentTime) {
this.currentTime = currentTime;
}
public void playWavFile(String fileName) {
playedWav = true;
}
public boolean wavWasPlayed() {
return playedWav;
}
public void resetWav() {
playedWav = false;
}
}
下面是一个调用getTime的具体类:
public class Checker {
private Environmental env;
public Checker(Environmental env) {
this.env = env;
}
public void reminder() {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(env.getTime());
int hour = cal.get(Calendar.HOUR_OF_DAY);
if (hour >= 17) {
env.playWavFile("quit_whistle.wav");
}
}
}
使用env.getTime()的被测代码并不知道测试环境和真实环境之间的区别,因为它们都实现了相同的接口。现在,你可以借助mock对象,通过把时间设置为已知值,并检查行为是否如预期那样来编写测试。
public class TestChecker extends TestCase {
public void testQuittingTime() {
MockSystemEnvironment env = new MockSystemEnvironment();
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 2006);
cal.set(Calendar.MONTH, 11);
cal.set(Calendar.DAY_OF_MONTH, 7);
cal.set(Calendar.HOUR_OF_DAY, 16);
cal.set(Calendar.MINUTE, 55);
//设置时间为16:55
long t1 = cal.getTimeInMillis();
System.out.println(t1);
env.setTime(t1);
Checker checker = new Checker(env);
checker.reminder();
assertFalse(env.wavWasPlayed());
//设置时间为17:00
t1 += (5 * 60 * 1000);
System.out.println(t1);
env.setTime(t1);
checker.reminder();
assertTrue(env.wavWasPlayed());
env.resetWav();
//设置时间为19:00
t1 += 2 * 60 * 60 * 1000;
System.out.println(t1);
env.setTime(t1);
checker.reminder();
assertTrue(env.wavWasPlayed());
}
}
这就是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 里就可以使用了(如下图所示&#