简介

JMockit是基于JavaSE5中的java.lang.instrument包开发,内部使用ASM库来动态修改java的字节码,使得java这种静态语言可以想动态脚本语言一样动态设置被Mock对象私有属性,模拟静态、私有方法行为等等website,参考这里;这里;

JMockit有两种Mock方式:基于行为的Mock方式和基于状态的Mock方式:

  1. (基于行为的)根据输入输出,功能测试,类似黑盒测试。需要把依赖的代码mock掉,实际相当于改变了被依赖的代码的逻辑。
  2. (基于状态的)根据用例测试路径,测试代码内部逻辑,接近白盒测试。目的是测试单元测试及其依赖代码的调用过程,验证代码逻辑是否满足测试路径。
测试解决方案
  1. Mock类的属性和行为(属性通过注入解决,行为通过对mock对象@Mocked覆盖方法)
  2. 手工注入(Deencapsulation.setField()方法)
  3. 单级注入(@Tested,@Injectable实现简单对象注入)
  4. 多级注入(需要mock对象,层层手工注入,单级注入不生效)
  5. 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的更多相关文章

  1. Jmockit使用

    引用单元测试中mock的使用及mock神器jmockit实践中的java单元测试中各种Mock框架对比,就能明白JMockit有多么强大: JMockit是基于JavaSE5中的java.lang.i ...

  2. 使用JUnit4与JMockit进行打桩测试

    1. 何为Mock 项目中各个模块,各个类之间会有互相依赖的关系,在单元测试中,我们只关心被测试的单元,对于其依赖的单元并不关心(会有另外针对该单元的测试). 比如,逻辑层A类依赖了数据访问层B类的取 ...

  3. JMockit使用总结

    Jmockit可以做什么 使用JMockit API来mock被依赖的代码,从而进行隔离测试. 类级别整体mock和部分方法重写 实例级别整体mock和部分mock mock静态方法.私有变量.局部方 ...

  4. jmockit学习

    下图为jmockit 类图.在我们编写代码时几乎都会用到Expectations(期望)和Verifications(校验),二者均继承自Invacations. 常会用到的注解有:@Mocked @ ...

  5. jmockit学习总结

    mock类型和实例 从依赖的测试代码调用的方法和构造函数是mock(模拟)的目标. Mocking提供了我们需要的机制,以便将被测试的代码与(一些)依赖关系隔离开来.我们通过声明适当的模拟字段和/或模 ...

  6. Jmockit之mock特性详解

    本文是Jmockit学习过程中,根据官网所列的工具特性进行解读. 1.调用次数约束(Invocation count constraints) 可以通过调用计数约束来指定预期和/或允许匹配给定期望的调 ...

  7. 单元测试系列:Mock工具Jmockit使用介绍

    更多原创测试技术文章同步更新到微信公众号 :三国测,敬请扫码关注个人的微信号,感谢! 原文链接:http://www.cnblogs.com/zishi/p/6760272.html Mock工具Jm ...

  8. JMockit常用操作

    JMockit常用操作 2017-11-30 转自:http://blog.csdn.net/foreverling/article/details/51234149 目录 1 基本概念  1.1 常 ...

  9. 单元测试系列之十一:Jmockit之mock特性详解

    本文是Jmockit学习过程中,根据官网所列的工具特性进行解读. 1.调用次数约束(Invocation count constraints) 可以通过调用计数约束来指定预期和/或允许匹配给定期望的调 ...

随机推荐

  1. close与shutdown函数

    linux网络编程之socket(十):shutdown 与 close 函数的区别  http://blog.csdn.net/yijiu0711/article/details/17349169 ...

  2. Qt qss 使用

    1.在资源文件建立一个qss文件.如blue.qss 2. 调用 #include "mainwindow.h" #include <QApplication> #in ...

  3. Java中时间日期格式化

    1.与日期时间相关的类:      第一:java.util.Date;                           将时间作为一个整体使用.处理时,使用Date类较为简便      第二:j ...

  4. ui router 介绍

    1. 路由规则 rap框架页面路由基于ui-router实现 1.1 ui-router 一个基本的路由状态如下所示: 路由配置: $stateProvider .state('po',{ url:' ...

  5. FFmpeg-20160415-snapshot-bin

    ESC 退出 0 进度条开关 1 屏幕原始大小 2 屏幕1/2大小 3 屏幕1/3大小 4 屏幕1/4大小 S 下一帧 [ -2秒 ] +2秒 ; -1秒 ' +1秒 下一个帧 -> -5秒 F ...

  6. [转]收集android上开源的酷炫的交互动画和视觉效果:Interactive-animation

    原文链接:http://www.open-open.com/lib/view/open1411443332703.html 描述:收集android上开源的酷炫的交互动画和视觉效果. 1.交互篇 2. ...

  7. [第三方]AFNetWorking3.0网络框架使用方法

    官网地址https://github.com/AFNetworking/AFNetworking #import <AFNetworking.h> - (void)viewDidLoad ...

  8. shiro错误总结

    今天在做spring+mybatis+springmvc+shiro的时候,报这个错,刚开始以为是shiro登录验证出错,后来,观看一下错误,发现在别的xml中写错了代码,shiro接连着报错,记录一 ...

  9. 混合高斯模型:opencv中MOG2的代码结构梳理

    /* 头文件:OurGaussmix2.h */ #include "opencv2/core/core.hpp" #include <list> #include&q ...

  10. 20145213祁玮のJava课程总结

    20145213のJava学习总结 每周学习笔记 1.第一周读书笔记 2.第二周读书笔记 3.第三周读书笔记 4.第四周读书笔记 5.第五周读书笔记 6.第六周读书笔记 7.第七周读书笔记 8.第八周 ...