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*/@Overridepublic User getUserByName(String name) {User userByName = userDao.getUserByName(name);if (userByName == null) {log.info("查询结果为空");throw new RuntimeException("查询结果为空");}return userByName;}/*** 保存user* @param user* @return*/@Overridepublic 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 {@InjectMocksprivate UserServiceImpl userService;@Mockprivate UserDao userDao;/*** 根据name查询user--1*/@Testpublic 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*/@Testpublic 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*/@Testpublic 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*/@Testpublic 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>
步骤
-
执行命令
-
点击进入具体的类中可以看到具体覆盖情况