Mockito由于其可以极大地简化单元测试的书写过程而被许多人应用在自己的工作中,但是Mockito工具不可以实现对静态函数、构造函数、私有函数、Final函数以及系统函数的模拟,但是这些方法往往是我们在大型系统中需要的功能。PowerMock就是在Mockito基础上扩展而来,通过定制类加载器等技术,PowerMock实现了上述所有模拟功能,使其成为分布式微服务架构必备的单元测试工具。
PowerMockito简单实例
PowerMock有两个重要的注解:
(1)@RunWith(PowerMockRunner.class)
(2)@PrepareForTest({ YourClassWithEgStaticMethod.class })
如果测试用例里没有使用注解@PrepareForTest,那么可以不用加注解@RunWith(PowerMockRunner.class),反之亦然。当需要使用PowerMock的强大功能(Mock静态、final、私有方法等)的时候,就需要加注解@PrepareForTest。使用PowerMock之前,需要在项目的pom.xml文件中添加依赖信息,具体代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.shrimpking</groupId>
<artifactId>demo9</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo9</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<exclusions>
<exclusion>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.5.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.5.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
接下来,我们来看具体的实例:
package com.shrimpking.powermock;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* Created by IntelliJ IDEA.
*
* @Author : Shrimpking
* @create 2024/1/14 11:00
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CvUser
{
private Integer id;
private String name;
}
package com.shrimpking.powermock;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by IntelliJ IDEA.
*
* @Author : Shrimpking
* @create 2024/1/14 10:59
*/
public class CvUserService
{
//当前调用次数
public AtomicInteger MAX_TIME;
public CvUser findUser(String name) throws Exception{
//findUser方法一天只能调用120次
if(MAX_TIME.get() > 120){
throw new Exception("系统繁忙");
}
CvUser cvUser = this.getUserFromDB();
Integer maxTime = this.MAX_TIME.getAndIncrement();
System.out.println("the current time is:" + maxTime);
return cvUser;
}
public AtomicInteger getMAX_TIME(){
return this.MAX_TIME;
}
public void setMAX_TIME(AtomicInteger MAX_TIME){
this.MAX_TIME = MAX_TIME;
}
public CvUser getUserFromDB(){
return new CvUser(1,"cv");
}
}
package com.shrimpking;
import com.shrimpking.powermock.CvUser;
import com.shrimpking.powermock.CvUserService;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by IntelliJ IDEA.
*
* @Author : Shrimpking
* @create 2024/1/14 10:51
*/
@SpringBootTest
public class PowerMockTest
{
@Test
public void testFindUser() throws Exception
{
//模拟对象
CvUserService cvUserService = PowerMockito.spy(new CvUserService());
//模拟对象赋值
Whitebox.setInternalState(cvUserService,"MAX_TIME",new AtomicInteger(100));
PowerMockito.when(cvUserService.getUserFromDB()).thenReturn(new CvUser(1,"cv"));
Assertions.assertThat(cvUserService.findUser("cv").getName()).isEqualTo("cv");
Whitebox.setInternalState(cvUserService,"MAX_TIME",new AtomicInteger(130));
String name = "cv";
try
{
PowerMockito.when(cvUserService,"findUser",name);
}catch (Exception e){
System.out.println(e.getMessage());
}
}
}
上述实例中,PowerMockito.spy用来模拟对象,Whitebox.setInternalState用来模拟给对象设置值,PowerMockito.when用来模拟方法内部的逻辑。