资讯详情

Java单元测试实践-05.Mockito、PowerMock基本功能使用

Java单元测试实践-00。目录(9万多字文档 700多个测试示例) https://blog.csdn.net/a82514921/article/details/107969340

1. Mockito与PowerMock的功能

以下用途Mockito与PowerMock作为单元测试Mock说明框架。

1.1. Mockito

参考 https://github.com/mockito/mockito/wiki/FAQ 。

Mockito是一个Java的Mock框架。支持对类或接口Mock,不支持静态方法、私有方法、构造函数等Mock。

1.2. PowerMock

参考 https://github.com/powermock/powermock/blob/release/2.x/README.md 。

PowerMock是一个Mock框架,以更强大的功能扩展了其他Mock库。PowerMock静态方法、构造函数、final类和方法、私有方法等进行Mock。PowerMock通过少量的方法和注释来扩展现有的API,使用额外的功能。目前,PowerMock支持EasyMock和Mockito。

PowerMock可查看示例: https://github.com/powermock/powermock-examples-maven 。

2. 添加引用

2.1. 引用Mockito

参考“Declaring mockito dependency”( https://github.com/mockito/mockito/wiki/Declaring-mockito-dependency )。

可以以下方式引用Mockito:

"org.mockito:mockito-core:1. " 

Mockito版本已更新到2.*与3.*,可使用新版本。

2.2. 引用PowerMock

参考“Mockito 2 Maven”( https://github.com/powermock/powermock/wiki/Mockito-2-Maven )。

对于使用Mockito 2.x,JUnit 4.4及以上版本引用以下方法PowerMock:

"org.powermock:powermock-module-junit4:2.0.4", "org.powermock:powermock-api-mockito2:2.0.4" 

3. PowerMock对Mockito的支持版本

参考“Supported versions”( https://github.com/powermock/powermock/wiki/Mockito#supported-versions )。

PowerMock的2.0.支持更高版本Mockito 2.具体版本支持关系可查看相应的表格。

4. 基本配置

在使用PowerMock以下公共配置通常用于(@ContextConfiguration是spring-test的配置):

@RunWith(PowerMockRunner.class) @PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { 
        "classpath:applicationContext.xml"}) @PowerMockIgnore({ 
        "javax.management.*", "javax.net.ssl.*", "javax.crypto.*", "javax.security.*", "javax.script.*"}) 

4.1. @RunWith(PowerMockRunner.class)

参考“Introduction”( https://github.com/powermock/powermock/wiki/mockito#introduction )。

PowerMock提供名为PowerMockito用于创建模拟/对象/类,并启动验证和期望。

所有用法都需要在类别级别中使用@RunWith(PowerMockRunner.class)和@PrepareForTest注解。

4.2. @PrepareForTest注解

参考“Annotation Type PrepareForTest”( https://javadoc.io/doc/org.powermock/powermock-core/latest/org/powermock/core/classloader/annotations/PrepareForTest.html )。

@PrepareForTest注解告诉PowerMock测试需要准备哪些类别。需要使用此注释定义的类通常需要操作字节码。final类,具有final、private、static或native实例化时应返回模拟对象的方法类和类。

@PrepareForTest可在测试类或单个测试方法中添加注释。如果设置在一个类中,测试类中的所有测试方法都将由PowerMock实现可测试性的处理。如果需要覆盖单一方法的行为,只需在特定的测试方法上设置即可@PrepareForTest注解。例如,在测试方法中f(1)修改类C但测试方法f2()方法可以保持C不变f在2()上设置一个@PrepareForTest注解,并从value()列表中的排除类C。

有时需要在测试中使用@PrepareForTest注释内部类的准备可以通过提供内部类的完整名称来完成,应该添加到名称中fullyQualifiedNames()列表中。

还可以用通配符准备整个程序包进行测试,如下:

@PrepareForTest(fullyQualifiedNames = ) 

@PrepareForTest注解可以添加在测试类,或测试类的超类中,子类与超类中的配置不会相互覆盖。

例如在子类中通过@PrepareForTest注解指定了A.class,在超类中指定了B.class,则A.class与B.class均会被@PrepareForTest注解处理。

可参考示例TestPrepareForTestChild、TestPrepareForTestParent类。

4.3. @PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)

参考“JUnit_Delegating_Runner”( https://github.com/powermock/powermock/wiki/junit_delegating_runner )。

使用@PowerMockRunnerDelegate注解,从1.6.0版开始,PowerMock支持将测试执行委托给另一个JUnit运行程序,而无需使用JUnit规则。这会将实际的测试执行留给选择的其他runner。例如,测试可以委托给“SpringJUnit4ClassRunner”,“Parameterized”或“Enclosed”等runner。

4.4. @PowerMockIgnore

参考“Global @PowerMockIgnore”( https://github.com/powermock/powermock/wiki/PowerMock-Configuration#global-powermockignore )。

默认情况下,PowerMock使用其MockClassLoader加载所有类。该类加载器加载并修改了所有类,除了以下情况:

  • 系统类。它们被延期到系统类加载器
  • 位于指定为忽略的程序包中的类

可以使用@PowerMockIgnore注解指定需要忽略的包,避免被PowerMock加载。

例如在调用加解密相关代码时,需要通过@PowerMockIgnore({“javax.crypto.*”})忽略上述包,否则会出现以下异常( 使用RSA私钥加密 ):

java.lang.ClassCastException: com.sun.crypto.provider.RSACipher cannot be cast to javax.crypto.CipherSpi

在调用HTTPS相关代码时,需要通过@PowerMockIgnore({“javax.security.*”})忽略上述包,否则会出现以下异常:

java.lang.LinkageError: loader constraint violation: loader (instance of org/powermock/core/classloader/javassist/JavassistMockClassLoader) previously initiated loading for a different type with name "javax/security/auth/x500/X500Principal"

若不忽略“javax.script.*”对应的包,在执行单元测试时可能会出现以下日志:

ScriptEngineManager providers.next(): javax.script.ScriptEngineFactory: Provider jdk.nashorn.api.scripting.NashornScriptEngineFactory not a subtype

5. Mock框架依赖组件、版本差别等

5.1. 依赖组件的影响

5.1.1. javassist

当在项目中添加groupId为“javassist”的javassist依赖时,会导致单元测试程序无法正常启动。

例如添加对“javassist:javassist:3.12.1.GA”的依赖,在启动单元测试程序时会出现以下异常:

java.lang.NoSuchMethodError: javassist.CtClass.getDeclaredClasses()[Ljavassist/CtClass;

at org.powermock.core.transformers.javassist.ConstructorsMockTransformer.transform(ConstructorsMockTransformer.java:50)

查看项目依赖的组件,同时依赖了“org.javassist:javassist:3.x.x-GA”与“javassist:javassist:3.12.1.GA”,前者由“org.powermock:powermock-core:2.x.x”间接依赖。

javassist从“3.12.1.GA”之后的版本“3.13.0-GA”开始,groupId由“javassist”变为“org.javassist”。

去除项目中对“javassist:javassist”的依赖后,单元测试程序启动正常。

5.2. Mockito 2与Mockito 1版本的区别

在 https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2#incompatible-changes-with-110 中,介绍了Mockito 2与Mockito 1.10版本不兼容的内容,其中常用的功能如下:

  • InvocationOnMock

在Mockito 1中,在Answer中使用的InvocationOnMock接口的实现类为InvocationImpl类,获取单个参数的方法为getArgumentAt();

在Mockito 2及以上版本中,InvocationOnMock接口的实现类为InterceptedInvocation类,获取单个参数的方法为getArgument()。

可参考示例TestCommonUtil类的getMockArg()方法,针对以上方法进行了兼容处理。

  • Mockito.any…()等方法是否支持null

对于Mockito.any…()及Mockito.any(SomeType.class)方法,在Mockito 1中支持null,在Mockito 2及以上版本中不支持null。

  • Mock/Spy对象的代理类名标志

Mock/Spy对象的代理类名标志,在Mockito 1中示例如下:

$$EnhancerByMockitoWithCGLIB$$96437470

在Mockito 2及以上版本中示例如下:

$MockitoMock$1151489917
  • Matchers/ArgumentMatcher类

在Mockito 1中,Mockito类继承自Matchers类;matches方法声明为“public abstract boolean matches(Object argument)”,在Matchers类中;isNotNull方法声明为“public static Object isNotNull()”;

在Mockito 2及以上版本中,Mockito类不继承自Matchers类,与Matchers类均继承自ArgumentMatchers类;matches方法声明为“public static String matches(Pattern pattern)”或“public static String matches(String regex)”,在ArgumentMatchers类中;isNotNull方法声明为“public static <T> T isNotNull()”。

5.3. PowerMock不同版本的区别

  • 需要添加的依赖组件不同

当使用Mockito 1版本时,需要添加的PowerMock依赖为“org.powermock:powermock-api-mockito”;当使用Mockito 2及以上版本时,需要添加的依赖为“org.powermock:powermock-api-mockito2”。

6. Mock与Stub

参考“Mocks Aren’t Stubs”( https://martinfowler.com/articles/mocksArentStubs.html#TheDifferenceBetweenMocksAndStubs )。Mock是用期望进行预编程的对象,这些对象构成了期望接收的调用的规范。Stub提供对测试过程中进行的调用的固定答复,通常不会对测试编程之外的内容进行响应。

参考“2. How about some stubbing?”( https://static.javadoc.io/org.mockito/mockito-core/latest/org/mockito/Mockito.html#stubbing )。Mock操作对应Mockito.mock()方法,Stub操作对应Mockito.when().thenReturn()/thenThrow()等方法。当方法被Stub后,将始终返回Stub的值,无论被调用多少次。

标签: powere继电器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台