针对如下代码进行单元测试编写:
package com.example.learn.privateMock;
public class EmployeeService {
public boolean exist(String userName) {
checkExist(userName);
return true;
}
private void checkExist(String name) {
throw new UnsupportedOperationException();
}
}
困难点是checkExist(String name)方法被private修饰,不能使用junit进行测试。
只能使用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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>LearnJavaDemo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
<jacoco.version>0.8.5</jacoco.version>
<powermock.version>2.0.7</powermock.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<jacoco.it.execution.data.file>${project.build.directory}/coverage-reports/jacoco-it.exec
</jacoco.it.execution.data.file>
<jacoco.ut.execution.data.file>${project.build.directory}/coverage-reports/jacoco-ut.exec
</jacoco.ut.execution.data.file>
<jdk.version>1.8</jdk.version>
<!--项目版本 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
</dependency>
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>org.jacoco.agent</artifactId>
<version>${jacoco.version}</version>
<classifier>runtime</classifier>
</dependency>
</dependencies>
<build>
<finalName>${project.name}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${jdk.version}</source>
<target>${jdk.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<executions>
<execution>
<id>default-instrument</id>
<goals>
<goal>instrument</goal>
</goals>
</execution>
<execution>
<id>default-restore-instrumented-classes</id>
<goals>
<goal>restore-instrumented-classes</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${project.build.directory}/coverage.exec</dataFile>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<systemPropertyVariables>
<jacoco-agent.destfile>${project.build.directory}/coverage.exec</jacoco-agent.destfile>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</project>
单元测试用例代码如下:
package com.example.learn.privateMock;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
@RunWith(PowerMockRunner.class)
@PrepareForTest({EmployeeService.class})
public class EmployeeServiceTest {
private final String userName = "zhangsan";
@Test
public void testSpyCheckExist() throws Exception {
// 通过.spy出的对象,调用自己的exist(userName)方法时,就会执行真的checkExist(String name)方法
EmployeeService service = PowerMockito.spy(new EmployeeService());
PowerMockito.doNothing().when(service,"checkExist", userName);
Assert.assertTrue(service.exist(userName));
PowerMockito.verifyPrivate(service,Mockito.times(1)).invoke("checkExist", userName);
}
@Test
public void testMockCheckExist() throws Exception {
EmployeeService service = PowerMockito.mock(EmployeeService.class);
PowerMockito.doNothing().when(service,"checkExist", userName);
/**
* 通过.mock出的对象,调用它自己的exist(userName)方法时,实际上调用的是exist(userName){}空方法,
* exist方法里面的逻辑并没有执行checkExist(String name),
* 而通过.spy出的对象,调用自己的exist(userName)方法时,就会执行真的checkExist(String name)方法
*/
service.exist(userName);
PowerMockito.verifyPrivate(service, Mockito.never()).invoke("checkExist", userName);
}
@Test
public void testCheckExistThrowExcept(){
try {
// 通过.spy出的对象,调用自己的exist(userName)方法时,就会执行真的checkExist(String name)方法
EmployeeService service = PowerMockito.spy(new EmployeeService());
service.exist(userName);
PowerMockito.verifyPrivate(service).invoke("checkExist", userName);
} catch (Exception e) {
Assert.assertTrue(e instanceof UnsupportedOperationException);
}
}
@Test
public void testCheckExistThrowExcept2(){
try {
// 通过.spy出的对象,调用自己的exist(userName)方法时,就会执行真的checkExist(String name)方法
EmployeeService service = PowerMockito.spy(new EmployeeService());
Whitebox.invokeMethod(service, "checkExist", userName);
PowerMockito.verifyPrivate(service).invoke("checkExist", userName);
} catch (Exception e) {
Assert.assertTrue(e instanceof UnsupportedOperationException);
}
}
}
使用命令行执行单元测试,并生成覆盖率:
mvn clean install
稍等片刻,在项目根目录下,target/site/jacoco/index.html生成覆盖率报告