简介

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. C++中的结构体

    http://zhidao.baidu.com/link?url=8OYQSKV9mvSBc6Hkf9NsLQmipSge9VCZDJQGAZZs5PCBQ54UTmK98VRmAklEEAFYu7d ...

  2. Apache2.4.6 添加虚拟主机

    apache2.4 与 apache2.2 的虚拟主机配置写法有所不同 apache2.2的写法: <VirtualHost *:80> ServerName domain.com Doc ...

  3. 10. javacript高级程序设计-DOM

    1. DOM DOM(文档对象模型)是针对HTML和XML文档的一个API(应用程序接口) 1.1 节点层次 DOM可以将任何HTML和XML文档描绘成一个由多层节点构成的结构.节点分为几种不同的类型 ...

  4. 【干货】ECS服务器OPENVPN搭建,方便管理所有内网服务器

    [干货]ECS服务器OPENVPN搭建,方便管理所有内网服务器 使用场景 一台有外网的ECS服务器+N台无外网的ECS服务器,使用OPENVPN管理全部的ECS服务器(包括无外网的ECS服务器). 鉴 ...

  5. mybatis 获取自增ID

    在Mybatis Mapper文件中添加属性“useGeneratedKeys”和“keyProperty”,其中keyProperty是Java对象的属性名,而不是表格的字段名. <inser ...

  6. App主界面Tab实现方法

    ViewPager + FragmentPagerAdapter 这里模仿下微信APP界面的实现 国际惯例,先看下效果图:   activity_main.xml 布局文件: <?xml ver ...

  7. IOS - SDWebImage 非ARC 问题

    非arc项目中使用SDWebImage类库 1.添加类库引用    (1)ImageIO.framework    (2)MapKit.framework 2.在targets->build P ...

  8. .net在当前日期的基础上加一天

    比如今天是:2015-11-10 18:57:01,在这个基础上加一天,那么就是2015-11-11 18:57:01,代码如下: DateTime now_dt = DateTime.Now; ). ...

  9. asp.net 防止按钮重复提交

    1.将按钮属性设置如下: <asp:Button ID="btConfirm" runat="server" Text="Confirm&quo ...

  10. vs c# int & int32

    在vs c#中,int就等价于int32, 所以通常也是使用int32 当在统计总数时,最好使用int32,int16数值范围太小,如果超出,就会变成随机数.