Java单元测试学习(二)
使用测试框架JUnit+Mockito和单元测试覆盖率框架JaCoCo
目录结构
依赖—很好,这里又有个小插曲
打开页面查看覆盖率时一直显示0/0---->最后的解决方式是①添加了maven-surefire-plugin插件
<?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.7.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>mocktio</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mocktio</name>
<description>Demo project for Spring Boot</description>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- test -->
<testcontainers.version>1.15.3</testcontainers.version>
<mockito.version>4.5.1</mockito.version>
<junit.version>4.12</junit.version>
<!-- redis -->
<commons.version>2.9.0</commons.version>
<!-- lombok -->
<lombok.version>1.18.12</lombok.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-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- testcontainers -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- spring2.X集成redis所需common-pool2-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<!--mockito依赖-->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<!-- jacoco -->
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- 单测覆盖率-->
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.6</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
相关代码
- UserDao
package com.example.mocktio.dao;
import com.example.mocktio.entity.User;
/**
* @author Snape
* @create 2023-06-06 11:02
* @desc
*/
public interface UserDao {
/**
* 根据name查找user
* @param name
* @return
*/
User getUserByName(String name);
/**
* 保存user
* @param user
* @return
*/
Integer saveUser(User user);
}
- User
package com.example.mocktio.entity;
import lombok.Data;
/**
* @author Snape
* @create 2023-06-06 10:58
* @desc
*/
@Data
public class User {
private String name;
private String sex;
private Integer age;
private String address;
}
- UserServiceImpl
package com.example.mocktio.service.impl;
import com.example.mocktio.dao.UserDao;
import com.example.mocktio.entity.User;
import com.example.mocktio.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* @author Snape
* @create 2023-06-06 11:07
* @desc
*/
@Slf4j
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
private final UserDao userDao;
/**
* 根据name查找user
* @param name
* @return
*/
@Override
public User getUserByName(String name) {
User userByName = userDao.getUserByName(name);
if (userByName == null) {
log.info("查询结果为空");
throw new RuntimeException("查询结果为空");
}
return userByName;
}
/**
* 保存user
* @param user
* @return
*/
@Override
public Integer saveUser(User user) {
if (userDao.getUserByName(user.getName()) != null) {
throw new RuntimeException("用户存在");
}
try {
return userDao.saveUser(user);
} catch (Exception e) {
throw new RuntimeException("保存用户异常");
}
}
}
- UserService
package com.example.mocktio.service;
import com.example.mocktio.entity.User;
import org.springframework.stereotype.Service;
/**
* @author Snape
* @create 2023-06-06 11:05
* @desc
*/
@Service
public interface UserService {
/**
* 根据name查找user
* @param name
* @return
*/
User getUserByName(String name);
/**
* 保存user
* @param user
* @return
*/
Integer saveUser(User user);
}
- application.properties为空
- MocktioApplication
package com.example.mocktio;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MocktioApplication {
public static void main(String[] args) {
SpringApplication.run(MocktioApplication.class, args);
}
}
- UserServiceTest
package com.example.mocktio.service.impl;
import com.example.mocktio.MocktioApplicationTests;
import com.example.mocktio.dao.UserDao;
import com.example.mocktio.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import static org.mockito.Mockito.*;
/**
* @author Snape
* @create 2023-06-06 11:12
* @desc
*/
@Slf4j
public class UserServiceTest extends MocktioApplicationTests {
@InjectMocks
private UserServiceImpl userService;
@Mock
private UserDao userDao;
/**
* 根据name查询user--1
*/
@Test
public void getUserByNameTest1() {
// mock对象stub操作
User user = new User();
user.setName("mockName");
user.setSex("mockSex");
user.setAge(18);
user.setAddress("mockAddress");
when(userDao.getUserByName("mockName")).thenReturn(user);
// 执行测试
User result = userService.getUserByName("mockName");
// 验证mock对象交互
verify(userDao).getUserByName(anyString());
// 验证查询结果
Assert.assertNotNull("查询结果为空!", result);
Assert.assertEquals("查询结果错误!", "mockSex", result.getSex());
Assert.assertEquals("查询结果错误!", Integer.valueOf(18), result.getAge());
Assert.assertEquals("查询结果错误!", "mockAddress", result.getAddress());
}
/**
* 根据name查询user--2
*/
@Test
public void getUserByNameTest2() throws Exception {
when(userDao.getUserByName("mockName")).thenReturn(null);
// 执行测试
try {
userService.getUserByName("mockName");
throw new Exception("测试失败");
} catch (RuntimeException e) {
log.info("查询结果为空-测试通过");
}
// 验证mock对象交互
verify(userDao).getUserByName(anyString());
}
/**
* 保存user--1
*/
@Test
public void saveUserTest1() throws Exception{
// mock对象stub操作
User user = new User();
user.setName("mockName");
when(userDao.getUserByName("mockName")).thenReturn(user);
// 验证用户重复的情况
try {
userService.saveUser(user);
throw new Exception("测试失败");
} catch (RuntimeException e) {
log.info("重复用户名保存失败-测试通过");
}
// 验证交互
verify(userDao).getUserByName("mockName");
}
/**
* 保存user--2
*/
@Test
public void saveUserTest2(){
// mock对象stub操作
when(userDao.getUserByName("mockName")).thenReturn(null);
when(userDao.saveUser(any(User.class))).thenReturn(1);
// 验证正常保存的情况
User user = new User();
user.setName("admin");
Integer integer = userService.saveUser(user);
Assert.assertEquals("保存失败!", 1, integer.longValue());
verify(userDao).saveUser(any(User.class));
verify(userDao, times(1)).getUserByName(anyString());
}
}
- MocktioApplicationTests
package com.example.mocktio;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest(
classes = MocktioApplication.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@RunWith(SpringRunner.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS)
@ExtendWith(SpringExtension.class)
public abstract class MocktioApplicationTests {
}
- testng.xml
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd" >
<suite name="Test Suite" verbose="1">
<test name="Test">
<classes>
<class name="com.example.mocktio.service.impl.UserServiceTest"/>
<class name="com.example.mocktio.MocktioApplicationTests"/>
</classes>
</test>
</suite>
步骤
-
执行命令
-
点击进入具体的类中可以看到具体覆盖情况