参考:Jmockit官网:JMockit技术的分享文章
大部分参考官网的知识,部分添加自己的理解。
JMockit是一款Java类/接口/对象的Mock工具,目前广泛应用于Java应用程序的单元测试中。
1. 当@Mocked修饰一个类时
例子:
@Mocked
Locale locale;
该类的所有的方法都被Mocked了,方法返回值都为null,就算是自已new一个该对象的实例,也同样如此,方法也都被mock了。
2. 当@Mocked修饰一个接口/抽象类时
接口/抽象类都被Mocked,方法返回值都为null,如果返回的是一个对象那么返回的这个对象也是被Mocked的对象。
注意:如果返回类型为原始类型(short,int,float,double,long)就返回0,如果返回类型为String就返回null,如果返回类型是其它引用类型,则返回这个引用类型的Mocked对象
3. @Injectable 与 @Mocked的不同
①@Injectable只是针对当前修饰的实例(也就是当前地址的实例,如果new一个新的对象实例的话,其并不受影响),而@Mocked是针对其修饰类的所有实例。
②@Injectable对类的静态方法,构造函数没有影响。因为它只影响某一个实例!
4. @Capturing主要用于子类/实现类的Mock
@Capturing的作用主要是对一个接口或者一个类进行Mock,并且对其所有的实例以及实现这个接口的类、子类进行Mock。
使用:一般在我们只知道父类或者接口时,但是我们还要控制这个父类或者接口的所有的子类或者接口的实现类的情况下进行使用,
5. Expectations:录制脚本规范和格式
例子:
6. Expectations主要有两种使用方式。
①通过引用外部类的Mock对象(@Injectabe,@Mocked,@Capturing)来录制(最常见的使用方式)
例子:最简单的使用方法
②当我想只Mock某个对象的某一个方法时
两种方法
1)把类传入Expectations的构造函数,如下图所示:
这种方法会把参数也作为录制条件,参数不同时方法的行为也不会被Mock,需要特别注意这一点。
注意:这种方法是针对这个类的所有的实例的某个方法,new一个新的实例,方法以及参数一致都会被Mock
2)把对象传入Expectations的构造函数,如下图所示:
这种方法只是针对某一个对象的Mock,如果new一个新的对象,该Mock就会失效。
7. Mockup和@Mock的方法更加简单直接。
图中的@Mock的方法十分简单直接在某个类上加上注解@Mock,就实现了对这个类的方法的Mock,也可以对Mock的方法进行逻辑定制,这种Mock方法可以解决大部分的需要Mock的场景。
但是我认为这种方法在测试大量的方法时会让测试代码很臃肿,甚至难以理解。
8. Verifications(用于验证Mock对象被调用的次数)
格式:
Verifications一般使用情况较少,一般都使用JUnit/TestNG/SpringTest的Assert类(断言)取代new Verifications() {{}}去验证代码块和代码的运行结果
9. @Tested
@Tested表示被测试对象,这里我的理解是这样的,比如说要测试一个订单的类的提交订单的方法能否实现时(此处省略具体的用例),在编写单元测试代码时,在编写Expectations之前(这里引用外部类的Mock对象,因为在大多是时候这种方法容易理解),将在实现提交订单之前的所有的服务进行Mock以用来确保提交订单这个方法能够正常的使用,而订单类自然而然作为我们要测试的对象就需要添加@Tested注解。
类似于这种,很明显我们真正测试的就是ApplyFeatureCoeTypeBean这个类,这里只是一个例子没有实际意义。
下面时官网的解释:
就是把@Injectable注解的内容注入到@Tested中去,使得测试对象的前置条件或方法被Mock,保证测试对象能够在不访问真正其他服务的情况下进行正常运行测试。
JMockit的常见使用
-
用Expectations来Mock。
这个例子使用的是将类传入Expectations的构造函数中的方法,这是比较常见的方法,需要注意是Expectations没办法Mock native和private方法。
※在实际中使用较多的还是通过引用外部类的Mock对象进行单测,这种方法更容易理解并且代码更简单。比如:
然后再在Expectations的构造函数中进行测试脚本的录入。
2. 用MockUp来Mock类
这种一般不建议这样写,但是其实都是可以的,因为我们在设计单元测试用例的时候就需要保证用例的单一性,一个用例只测试一种情况,正常来说是不会涉及到太多的方法,但是还是存在较多的情况,这种MockUp的方法就会使得代码十分臃肿,增加测试的复杂度,不推荐这样使用。
但是MockUp可以直接对方法进行逻辑覆盖,所以在实际单元测试的时候要根据实际的测试内容和用例来选择JMockit方法。