JMockit
简介
JMockit是基于JavaSE5中的java.lang.instrument包开发,内部使用ASM库来动态修改java的字节码,使得java这种静态语言可以想动态脚本语言一样动态设置被Mock对象私有属性,模拟静态、私有方法行为等等website,参考这里;这里;
JMockit有两种Mock方式:基于行为的Mock方式和基于状态的Mock方式:
- (基于行为的)根据输入输出,功能测试,类似黑盒测试。需要把依赖的代码mock掉,实际相当于改变了被依赖的代码的逻辑。
- (基于状态的)根据用例测试路径,测试代码内部逻辑,接近白盒测试。目的是测试单元测试及其依赖代码的调用过程,验证代码逻辑是否满足测试路径。
测试解决方案
- Mock类的属性和行为(属性通过注入解决,行为通过对mock对象
@Mocked覆盖方法) - 手工注入(Deencapsulation.setField()方法)
- 单级注入(@Tested,@Injectable实现简单对象注入)
- 多级注入(需要mock对象,层层手工注入,单级注入不生效)
- Mock接口(覆盖率插件可能会抛错,Mock实现类,返回接口类型)
关键字:@Tested,@Injectable,Expectations类,@Mocked{result,times,invoke()}, MokeUp<T>
基于行为的Mock方式
1.录制方法预期行为。
2.真实调用。
3.验证录制的行为被调用。
public class GuessTest {
@Tested // 表明被修饰实例是将会被自动构建和注入的实例,自动Mock
Guess guess = new Guess(3);
@Injectable // 表明被修饰实例将会自动注入到@Tested修饰的实例中,并且会自动mock掉,除非在测试前被赋值
GuessDAO guessDAO;
/**
* 连续3次失败
*/
@Test
public void behaviorTest_fail3time() {
new Expectations() { // Expectations中包含的内部类区块中,体现的是一个录制被测类的逻辑。
@Mocked(methods="tryIt") // 表明被修饰的类对tryIt()方法进行mock。
Guess g;
{
g.tryIt(); // 期待调用Guess.tryIt()方法
result = false; // mock掉返回值为false(表明猜不中)
times = 3; // 期待以上过程重复3次
guessDAO.saveResult(false, anyInt); // 期待调用guessDAO把猜失败的结果保存
}
};
guess.doit(); // 录制完成后,进行实际的代码调用,也称回放(replay)
}
}
@Tested和@Injectable:
对@Tested对象判断是否为null,是则通过合适构造器初始化,并实现依赖注入。调用构造方法时,会尝试使用@Injectable的字段进行构造器注入。普通注入时,@Injectable字段如果没有在测试方法前被赋值,其行为将会被mock成默认值(静态方法和构造函数不会被mock掉)。Injectable最大作用除了注入,还有就是mock的范围只限当前注释实例。
总结为:@Injectable的实例会自动注入到@Tested中,如果没初始赋值,那么JMockit将会以相应规则初始化。
@Mocked:@Mocked修饰的实例,将会把实例对应类的所有实例的所有行为都mock掉(无论构造方法,还是private,protected方法,够霸气吧)。在Expectation区块中,声明的成员变量均默认带有@Mocked,但是本例没有省略,是因为@Mocked会mock掉所有方法,而回放的代码中doit函数我们是不希望它也被mock,所以通过method="tryIt"来设置被mock的类只对tryIt方法进行mock。
Expectations:这是录制期望发生行为的地方。result和times都是其内定成员变量。result可以重定义录制行为的返回值甚至通过Delegate来重定义行为,times是期待录制行为的发生次数。在Expectations中发生的调用,均会被mock。由于没定义result,所以guessDAO.saveResult()调用的结果返回空。
方法二(基于行为的)
@Test
public void behaviorTest_sucecess() {
new Expectations(Guess.class) { // 构造函数可以传入Class或Instance实例
{
guess.tryIt();
result = false;
times=2;
invoke(guess, "randomGuess", new Object[]{}); // invoke()能调用私有方法
result = (Integer)getField(guess, "number"); // getField()能操作私有成员
guessDAO.saveResult(true, (Integer)getField(guess, "number"));
}
};
guess.doit();
}
所以录制中会先调用2次tryIt并返回false,在发生第3次调用时,通过invoke调用私有方法randomGuess,并期待其返回被测实例的私有成员number,通过这种作弊的方式,自然肯定能在第三次猜中数字。最后期待guessDAO把结果保存。
这段代码和之前的区别是,在Expectation中没定义成员变量,而把Guess.class显式地通过构造函数传入。这么做也是为了只对tryIt方法mock,因为在Expectation构造函数传入Class对象或Instance对象后,只会区块内Class或Instance对应的行为进行mock。
方法三(基于状态的)
使用MockUp,@Mock。通过这种方式,改变方法内部逻辑,实现类似白盒测试的功能。MockUp中的泛型类型是被重定义的类,重定义的方法需要和原类中的方法签名一致。但是,static方法可以省去static关键字。如:
public class StateMocked {
public static int getDouble(int i){
return i*2;
}
}
@Test
public void testMockNormalMethodContent() throws IOException {
StateMocked obj = new StateMocked();
new MockUp<StateMocked>() {//使用MockUp修改被测试方法内部逻辑
@Mock
public int getTriple(int i) {
return i * 30;
}
};
assertEquals(30, obj.getTriple(1));
assertEquals(60, obj.getTriple(2));
}
JMockit的更多相关文章
- Jmockit使用
引用单元测试中mock的使用及mock神器jmockit实践中的java单元测试中各种Mock框架对比,就能明白JMockit有多么强大: JMockit是基于JavaSE5中的java.lang.i ...
- 使用JUnit4与JMockit进行打桩测试
1. 何为Mock 项目中各个模块,各个类之间会有互相依赖的关系,在单元测试中,我们只关心被测试的单元,对于其依赖的单元并不关心(会有另外针对该单元的测试). 比如,逻辑层A类依赖了数据访问层B类的取 ...
- JMockit使用总结
Jmockit可以做什么 使用JMockit API来mock被依赖的代码,从而进行隔离测试. 类级别整体mock和部分方法重写 实例级别整体mock和部分mock mock静态方法.私有变量.局部方 ...
- jmockit学习
下图为jmockit 类图.在我们编写代码时几乎都会用到Expectations(期望)和Verifications(校验),二者均继承自Invacations. 常会用到的注解有:@Mocked @ ...
- jmockit学习总结
mock类型和实例 从依赖的测试代码调用的方法和构造函数是mock(模拟)的目标. Mocking提供了我们需要的机制,以便将被测试的代码与(一些)依赖关系隔离开来.我们通过声明适当的模拟字段和/或模 ...
- Jmockit之mock特性详解
本文是Jmockit学习过程中,根据官网所列的工具特性进行解读. 1.调用次数约束(Invocation count constraints) 可以通过调用计数约束来指定预期和/或允许匹配给定期望的调 ...
- 单元测试系列:Mock工具Jmockit使用介绍
更多原创测试技术文章同步更新到微信公众号 :三国测,敬请扫码关注个人的微信号,感谢! 原文链接:http://www.cnblogs.com/zishi/p/6760272.html Mock工具Jm ...
- JMockit常用操作
JMockit常用操作 2017-11-30 转自:http://blog.csdn.net/foreverling/article/details/51234149 目录 1 基本概念 1.1 常 ...
- 单元测试系列之十一:Jmockit之mock特性详解
本文是Jmockit学习过程中,根据官网所列的工具特性进行解读. 1.调用次数约束(Invocation count constraints) 可以通过调用计数约束来指定预期和/或允许匹配给定期望的调 ...
随机推荐
- close与shutdown函数
linux网络编程之socket(十):shutdown 与 close 函数的区别 http://blog.csdn.net/yijiu0711/article/details/17349169 ...
- Qt qss 使用
1.在资源文件建立一个qss文件.如blue.qss 2. 调用 #include "mainwindow.h" #include <QApplication> #in ...
- Java中时间日期格式化
1.与日期时间相关的类: 第一:java.util.Date; 将时间作为一个整体使用.处理时,使用Date类较为简便 第二:j ...
- ui router 介绍
1. 路由规则 rap框架页面路由基于ui-router实现 1.1 ui-router 一个基本的路由状态如下所示: 路由配置: $stateProvider .state('po',{ url:' ...
- FFmpeg-20160415-snapshot-bin
ESC 退出 0 进度条开关 1 屏幕原始大小 2 屏幕1/2大小 3 屏幕1/3大小 4 屏幕1/4大小 S 下一帧 [ -2秒 ] +2秒 ; -1秒 ' +1秒 下一个帧 -> -5秒 F ...
- [转]收集android上开源的酷炫的交互动画和视觉效果:Interactive-animation
原文链接:http://www.open-open.com/lib/view/open1411443332703.html 描述:收集android上开源的酷炫的交互动画和视觉效果. 1.交互篇 2. ...
- [第三方]AFNetWorking3.0网络框架使用方法
官网地址https://github.com/AFNetworking/AFNetworking #import <AFNetworking.h> - (void)viewDidLoad ...
- shiro错误总结
今天在做spring+mybatis+springmvc+shiro的时候,报这个错,刚开始以为是shiro登录验证出错,后来,观看一下错误,发现在别的xml中写错了代码,shiro接连着报错,记录一 ...
- 混合高斯模型:opencv中MOG2的代码结构梳理
/* 头文件:OurGaussmix2.h */ #include "opencv2/core/core.hpp" #include <list> #include&q ...
- 20145213祁玮のJava课程总结
20145213のJava学习总结 每周学习笔记 1.第一周读书笔记 2.第二周读书笔记 3.第三周读书笔记 4.第四周读书笔记 5.第五周读书笔记 6.第六周读书笔记 7.第七周读书笔记 8.第八周 ...