欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

全面解析JMockit

最编程 2024-01-19 15:03:43
...

1、基于状态的Mock:

是站在目标测试代码内部的,可以对传入的参数进行检查、匹配,才返回某些结果,类似白盒。

主要使用MockUp和@Mock搭配使用实现Mock

2、基于行为的Mock:

就是对Mock目标代码的行为进行模仿,更像是黑盒测试。

主要使用@Test @Mocked @Intectable @Capuring和Expectations搭配使用实现Mock

总结:

其实从大的方向来讲,JMockit只有两种Mock方式:new MockUp()和new Expectations()两种

     (1)注解@Mock是和new MockUp()方式搭配使用。

       (2)注解@Test  @Mocked  @Injectable @Caturing是和new Expections()方式搭配使用。然后@Mocked @Intectable  @Capturing又有不同的特性,就可以解决不同场景下的Mock了。

场景:下面来通过一个最简单的单元测试场景来学习JMockit的使用;

现在有一个类,我们需要对其中的公有方法、持有方法、静态方法、final方法进行Mock.

1、基于状态的Mock
这种写法我觉得非常简洁明了,而且已经能解决绝大部分的单元测试的需求了。针对不能解决的应用场景在后面也会分析。
要讲基于状态的Mock,那么肯定是要明白MockUp和@Mock的作用和优缺点。

作用:
如果我们想对Java中某个类的某个方法进行定制,只需要把该类传入MockUp类的构造函数即可。然后想Mock哪个方法,就在哪个方法上加@Mock注解。没有加@Mock注解的方法不会受影响。

原理:
JMockit在new MockUp()装载的类中的每个方法(只要是经@Mock修饰过的)中插入了一个分支,这个分支就是走MockUp类(即new MockUp{{}}匿名类或extends MockUp的子类)的mock方法,因此就达到了Mock的目的。

总结:
使用MockUp实现类中方法的Mock,
(1)可以对指定方法进行Mock。想Mock哪个方法就在哪个方法上加@Mock。不加则不受影响。
(2)对该类的所有对象都生效。无论是依赖注入或者new的多个实例对象,都会生效。

缺点:
(1)一个类多个实例情况。因为是对该类的所有实例都有效,所以如果想对一个类的多个实例有不同的操作的时候,这种写法就很不适用了。
(2)AOP动态生成的类。通过AOP动态生成的类,很可能我们连名称是什么都不知道,更不用提如何适用MockUp进行Mock啦。
(3)需要Mock的方法过多。如果需要Mock的方法过多,我们就要写很多很多代码,很不方便。

适用场景:
其实掌MockUp和@Mock就能帮我们解决大部分的Mock场景,而且使用方式直接明了。
这种方式比较适用于对通用类的方法进行Mock。

2、基于行为的Mock
根据上面方希,基于状态的Mock(通过MockUp和@Mock方式)存在多种无法适用的场景。JMockit还提供基于行为的Mock方式。
要讲基于状态的Mock,那么肯定是要明白Expectations和@Test、@Mocked、@Injectable、@Capturing的作用和优缺点。

示例:
根据我自己测试来看,如果导包的时候JMockit在JUnit后面,则如果想使用测试参数和@Test、@Mocked、@Injectable、@Capturing注解,必须添加在测试类上添加@RunWith(JMockit.class)注解。否则会不支持测试方法和注解的属性NullPointerException。但是使用上一节的MockUp方式则不必要。

i

代码总结:

(1)在JMockit中,我们可以用JMockit的注解API来修饰它。这些API有@Mocked, @Tested, @Injectable, @Capturing。不同的注解有不同的含义。

(2)在上述例子中,我们用@Mocked修饰了测试属性HelloJMockit helloJMockit,表示helloJMockit这个测试属性,它的实例化,属性赋值,方法调用的返回值全部由JMockit来接管,接管后,helloJMockit的行为与HelloJMockit类定义的不一样了,而是由录制脚本来定义了。

(3)给测试方法加参数,原本在JUnit中是不允许的,但是如果参数加了JMockit的注解API(@Mocked, @Tested,@Injectable,@Capturing)后,则是允许的。

通常,在实际测试程序中,我们更倾向于通过JUnit/TestNG/SpringTest的Assert类对测试结果的验证, 对类的某个方法有没调用,调用多少次的测试场景并不是太多。因此在验证阶段,我们完全可以用JUnit/TestNG/SpringTest的Assert类取代new Verifications() {{}}验证代码块。除非,你的测试程序关心类的某个方法有没有调用,调用多少次,你可以使用new Verifications() {{}}验证代码块。如果你还关心方法的调用顺序,你可以使用new VerificationsInOrder() {{}} .这里就不做详细的介绍了。

(1)测试属性&测试参数
a)测试属性:即测试类的一个属性。它作用于测试类的所有测试方法。
b)测试参数:即测试方法的参数。它仅作用于当前测试方法。

(2)Record-Replay-Verification结构
在JMockit单元测试中最常见的写法:录制代码块,重放测试逻辑,验证代码块。Record-Replay-Verification 是JMockit测试程序的主要结构。
a)Record: 即先录制某类/对象的某个方法调用,在当输入什么时,返回什么。
b)Replay: 即重放测试逻辑。
c)Verification: 重放后的验证。比如验证某个方法有没有被调用,调用多少次。
其实,Record-Replay-Verification与JUnit程序的AAA(Arrange-Action-Assert)结构是一样的。
Record对应Arrange,先准备一些测试数据,测试依赖。Replay对应Action,即执行测试逻辑。Verification对应Assert,即做测试验证。

(3)注解@Mocked, @Tested, @Injectable, @Capturing的区别与用法
注解@Mocked的说明
解释:

使用@Mocked可以修饰类、接口、抽象类。
使用@Mocked修饰,就是告诉JMockit生成一个Mocked对象,这个对象方法(包含静态方法,私有方法)都返回默认值。
如果返回类型为原始类型(short、int、float、double、long),则返回0。
如果返回类型为String类型,则返回null。
如果返回类型是其他引用类型,则返回这个引用类型的Mocked对象。(这里就又需要Mock这个对象,就这样递归的定义下去)
注意:

使用@Mocked修饰是对该类的所有实例都生效的。
但是如果被@Mock修饰的对象是作为参数传入Expectations构造函数中时,会只针对该对象有效。
应用场景:
当我们的测试程序依赖某个接口时,用@Mocked非常适合了。只需要@Mocked一个注解,JMockit就能帮我们生成这个接口的实例。

Expectations主要有两种使用方式:

通过引用外部类的Mock对象(@Injectabe,@Mocked,@Capturing)来录制
对类的所有方法都mock了
通过构建函数注入类/对象来录制
把待Mock的类传入Expectations的构造函数,可以达到只mock类的部分行为的目的

注解@Tested的说明
使用@Tested修饰的类,表示我们要测试对象。JMockit也会帮我们实例化这个测试对象。

如何实例化@Tested修饰的类:

如果该对象没有赋值,就去实例化它。
首先,对构造函数实例化。
若@Test对象的构造函数有参数,则JMockit通过测试属性和测试参数中查找@Injectable修饰的Mocked对象注入@Tested对象的构造函数来实例化。
若@Test对象的构造函数没有参数,则用无参构造函数来实例化。
然后,需要将@Tested对象中其他字段属性注入。
JMockit通过属性查找的方式,把@Injectable对象注入到@Tested对象中。
注入的匹配规则:先类型,再名称(构造函数参数名,类的属性名)。若找到多个可以注入的@Injectable,则选择最优先定义的@Injectable对象。
注意:
当然,我们的测试程序要尽量避免这种情况出现。
因为给哪个测试属性、测试参数加@Injectable,是人为控制的

应用场景:
当我们需要手动管理被测试类的依赖时,就需要用到@Tested和@Injectable。
两者搭配使用,JMockit就能帮我们轻松搞定被测试类及其依赖注入细节。

@Tested & @Injectable 搭配使用
其实,我们在使用的过程中,往往将@Tested & @Injectable 搭配使用。

注解@Capturing的说明
应用场景:
注解@Capturing主要用于子类/实现类的Mock我们只知道父类或接口时,但我们却需要控制它所有子类的行为时,子类可能有多个实现(可能有人工写的,也可能是AOP代理自动生成时),就用@Capturing。

示例1:
其实我从来没用过哈哈哈哈。借用一下JMockit中文网的代码。

原文地址:https://www.cnblogs.com/itjiaxu/p/16251190.html