当前位置: 首页 > article >正文

企业级单元测试流程

企业级的单元测试流程不仅是简单编写测试用例,而是一整套系统化、自动化、可维护、可度量的工程实践,贯穿从代码编写到上线部署的全生命周期。下面是一个尽可能完善的 企业级单元测试流程设计方案,适用于 Java 生态(JUnit + Mockito 为核心):

✅ 1. 测试策略制定(Test Strategy)
测试金字塔模型:

单元测试(Unit Test)70%

集成测试(Integration Test)20%

端到端测试(E2E Test)10%

测试目标:保证核心业务逻辑的正确性、边界覆盖、异常处理、性能边界、并发情况等。

编码规范:团队定义统一的测试命名规范、mock 模式、断言风格、CI 阈值等。

✅ 2. 项目结构与规范

src/
main/java/… # 业务代码
test/java/… # 测试代码(包结构一致)
每个业务类必须有对应的 xxxTest 测试类

命名规范:methodName_scenario_expectedOutcome

示例:

@Test
void getUserById_whenUserExists_shouldReturnUser() { … }
✅ 3. 工具链与依赖配置
✅ 推荐依赖(以 Maven 为例):
xml
复制
编辑

org.junit.jupiter
junit-jupiter
5.10.0
test

org.mockito mockito-core 5.5.0 test org.assertj assertj-core 3.24.2 test ✅ 4. 单元测试设计原则 原则 说明 FAST 快速执行(单元测试每次 <200ms) ISOLATED 不依赖数据库、外部服务等 REPEATABLE 可重复运行,不依赖执行顺序 SELF-VALIDATING 自动断言,无需人工判断 TIMELY 与开发同步完成,不能补测试

✅ 5. Mock 与 Stub 策略
使用 Mockito 或 EasyMock 替换外部依赖(如 DAO、RestTemplate、消息中间件等)

只 mock “真正的依赖对象”,不要 mock 被测试类

不建议 mock 静态类(可以考虑使用 PowerMock 或重构)

@ExtendWith(MockitoExtension.class)
class UserServiceTest {

@Mock
private UserRepository userRepository;@InjectMocks
private UserService userService;@Test
void getUserById_shouldReturnUser() {User user = new User(1L, "Tom");when(userRepository.findById(1L)).thenReturn(Optional.of(user));User result = userService.getUserById(1L);assertThat(result.getName()).isEqualTo("Tom");
}

}
✅ 6. 测试覆盖率与静态分析
工具 功能
JaCoCo 生成代码覆盖率报告(class/line/branch)
SonarQube 静态分析 + 质量门槛 + 技术债务管理
Pitest mutation 测试,检查测试的“有效性”

在 CI/CD 中设置最低覆盖率阈值(如 80%)

报告纳入 MR/PR 审查流程

✅ 7. 集成 CI/CD 流程
在 Jenkins / GitLab CI / GitHub Actions 中配置以下步骤:

steps:

  • checkout
  • run: ./mvnw test
  • run: ./mvnw jacoco:report
  • run: ./mvnw sonar:sonar
    触发策略:

每次提交触发自动测试

阻止代码 merge 如果测试失败或覆盖率下降

✅ 8. 失败回溯与日志调试
建议所有测试类打印完整错误栈(不要吞异常)

添加断点调试单测功能(IDE 支持)

使用日志切面记录关键 Mock 行为

✅ 9. 常见高级用法
用法 描述
参数化测试(@ParameterizedTest) 一组输入,多组断言
断言异常(assertThrows) 验证异常逻辑
动态测试(DynamicTest) 运行时生成测试用例
时间限制(assertTimeout) 防止慢测试

✅ 10. 企业常见实践建议
建议 理由
单测与功能开发同步完成 不留技术债
MR/PR 中必须展示覆盖率 透明可控
所有 Bug 必须有回归测试 防止重复出错
通用工具类单测由架构组维护 保持通用测试的权威性
每月自动分析测试健康度 防止测试代码腐化

📦 示例工程(推荐结构)

project-root/

├── src/
│ ├── main/java/com/example/service/UserService.java
│ └── test/java/com/example/service/UserServiceTest.java

├── pom.xml
└── sonar-project.properties

maven dependency

// 文件: pom.xml
<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>com.example</groupId><artifactId>local-knowledge-base</artifactId><version>1.0-SNAPSHOT</version><properties><java.version>17</java.version><junit.jupiter.version>5.10.0</junit.jupiter.version><mockito.version>5.5.0</mockito.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>${junit.jupiter.version}</version><scope>test</scope></dependency><dependency><groupId>org.mockito</groupId><artifactId>mockito-core</artifactId><version>${mockito.version}</version><scope>test</scope></dependency><dependency><groupId>org.assertj</groupId><artifactId>assertj-core</artifactId><version>3.24.2</version><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.jacoco</groupId><artifactId>jacoco-maven-plugin</artifactId><version>0.8.11</version><executions><execution><goals><goal>prepare-agent</goal></goals></execution><execution><id>report</id><phase>verify</phase><goals><goal>report</goal></goals></execution></executions></plugin></plugins></build>
</project>// 文件: src/test/java/com/example/service/UserServiceTest.java
package com.example.service;import com.example.model.User;
import com.example.repository.UserRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;import java.util.Optional;import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.*;@ExtendWith(MockitoExtension.class)
class UserServiceTest {@Mockprivate UserRepository userRepository;@InjectMocksprivate UserService userService;@Testvoid getUserById_whenUserExists_shouldReturnUser() {User user = new User(1L, "Tom");when(userRepository.findById(1L)).thenReturn(Optional.of(user));User result = userService.getUserById(1L);assertThat(result.getName()).isEqualTo("Tom");}@Testvoid getUserById_whenUserNotExists_shouldThrow() {when(userRepository.findById(anyLong())).thenReturn(Optional.empty());assertThrows(RuntimeException.class, () -> userService.getUserById(99L));}
}// 文件: .github/workflows/ci.yml
name: CIon:push:branches: [ main ]pull_request:branches: [ main ]jobs:build-and-test:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4- name: Set up JDK 17uses: actions/setup-java@v4with:distribution: 'temurin'java-version: '17'- name: Build with Mavenrun: mvn clean verify- name: Generate coverage reportrun: mvn jacoco:report- name: Upload coverage to SonarQuberun: mvn sonar:sonar -Dsonar.login=${{ secrets.SONAR_TOKEN }}// 文件: sonar-project.properties
sonar.projectKey=local-knowledge-base
sonar.sources=src/main/java
sonar.tests=src/test/java
sonar.java.coveragePlugin=jacoco
sonar.jacoco.reportPaths=target/jacoco.exec

推荐教程和书籍:

1.《Mastering Unit Testing Using Mockito and JUnit》:这本书深入探讨了使用 JUnit 和 Mockito 进行单元测试的高级技巧,包括自动化测试、持续集成和代码质量监控等方面。
亚马逊印度

2.Baeldung 的 JUnit 教程:提供了丰富的 JUnit 教程和最佳实践,适合不同水平的开发人员学习。

3.AWS 官方白皮书:详细介绍了在 AWS 上实践持续集成和持续交付的测试阶段,适合希望在云环境中实施 CI/CD 的团队参考。
docs.aws.amazon.com

相关文章:

企业级单元测试流程

企业级的单元测试流程不仅是简单编写测试用例&#xff0c;而是一整套系统化、自动化、可维护、可度量的工程实践&#xff0c;贯穿从代码编写到上线部署的全生命周期。下面是一个尽可能完善的 企业级单元测试流程设计方案&#xff0c;适用于 Java 生态&#xff08;JUnit Mockit…...

安卓开发用到的设计模式(2)结构型模式

安卓开发用到的设计模式&#xff08;2&#xff09;结构型模式 文章目录 安卓开发用到的设计模式&#xff08;2&#xff09;结构型模式1. 适配器模式&#xff08;Adapter Pattern&#xff09;2. 装饰器模式&#xff08;Decorator Pattern&#xff09;3. 代理模式&#xff08;Pro…...

JavaWeb:SpringBoot配置优先级详解

3种配置 打包插件 命令行 优先级 SpringBoot的配置优先级决定了不同配置源之间的覆盖关系&#xff0c;遵循高优先级配置覆盖低优先级的原则。以下是详细的优先级排序及配置方法说明&#xff1a; 一、配置优先级从高到低排序 1.命令行参数 优先级最高&#xff0c;通过keyvalu…...

故障率预测:基于LSTM的GPU集群硬件健康监测系统(附Prometheus监控模板)

一、GPU集群健康监测的挑战与价值 在大规模深度学习训练场景下&#xff0c;GPU集群的硬件故障率显著高于传统计算设备。根据2023年MLCommons统计&#xff0c;配备8卡A100的服务器平均故障间隔时间&#xff08;MTBF&#xff09;仅为1426小时&#xff0c;其中显存故障占比达38%&…...

【b站计算机拓荒者】【2025】微信小程序开发教程 - chapter3 项目实践 -1 项目功能描述

1 项目功能描述 # 智慧社区-小程序-1 欢迎页-加载后端&#xff1a;动态变化-2 首页-轮播图&#xff1a;动态-公共栏&#xff1a;动态-信息采集&#xff0c;社区活动&#xff0c;人脸检测&#xff0c;语音识别&#xff0c;心率检测&#xff0c;积分商城-3 信息采集页面-采集人数…...

FFmpeg 安装包全攻略:gpl、lgpl、shared、master 区别详解

这些 FFmpeg 安装包有很多版本和变种&#xff0c;主要区别在于以下几个方面&#xff1a; ✅ 一、从名称中看出的关键参数&#xff1a; 1. 版本号 master&#xff1a;开发版&#xff0c;最新功能&#xff0c;但可能不稳定。n6.1 / n7.1&#xff1a;正式版本&#xff0c;更稳定…...

AI浪潮下,媒体内容运营的五重变奏

算法驱动的个性化推荐 在信息爆炸的时代,用户面临着海量的内容选择,如何让用户快速找到感兴趣的人工智能内容,成为媒体运营的关键。算法驱动的个性化推荐模式应运而生,它通过分析用户的行为数据,如浏览历史、点赞、评论、搜索关键词等,构建用户兴趣画像 ,再依据画像为用…...

WindTerm 以 SSH 协议的方式通过安恒明御堡垒机间接访问服务器

1. 配置堡垒机秘钥 创建公私钥ssh-keygen -t rsa -b 4096执行完该命令后按照提示一路回车就能够创建出公私钥注意&#xff1a;在创建过程中会让你指定秘钥的存储位置以及对应的密码&#xff0c;最好自行指定一下 id_rsa 是私钥id_rsa.pub 是公钥 在堡垒机中指定创建好的私钥 …...

通过现代数学语言重构《道德经》核心概念体系,形成一个兼具形式化与启发性的理论框架

以下是对《道德经》的数学转述尝试&#xff0c;通过现代数学语言重构其核心概念&#xff0c;形成一个兼具形式化与启发性的理论框架&#xff1a; 0. 基础公理体系 定义&#xff1a; 《道德经》是一个动态宇宙模型 U(D,V,Φ)&#xff0c;其中&#xff1a; D 为“道”的无限维…...

邂逅Node.js

首先先要来学习一下nodejs的基础&#xff08;和后端开发有联系的&#xff09; 再然后的学习路线是学习npm&#xff0c;yarn&#xff0c;cnpm&#xff0c;npx&#xff0c;pnpm等包管理工具 然后进行模块化的使用&#xff0c;再去学习webpack和git&#xff08;版本控制工具&…...

计算机视觉(图像算法工程师)学习路线

计算机视觉学习路线 Python基础 常量与变量 列表、元组、字典、集合 运算符 循环 条件控制语句 函数 面向对象与类 包与模块Numpy Pandas Matplotlib numpy机器学习 回归问题 线性回归 Lasso回归 Ridge回归 多项式回归 决策树回归 AdaBoost GBDT 随机森林回归 分类问题 逻辑…...

GITLIbCICD流水线搭建

1&#xff0c;搭建gitLIb服务器&#xff0c;创建gitlibRunner 并且注册&#xff0c; 2. 写dockerfile 包块java程序运行的环境&#xff0c;jdk&#xff0c;参数等 &#xff0c; 2.1ai生成版本&#xff0c; # 基础镜像&#xff08;JDK 17&#xff09;FROM eclipse-temurin:1…...

详细介绍Qwen3技术报告中提到的模型架构技术

详细介绍Qwen3技术报告中提到的一些主流模型架构技术&#xff0c;并为核心流程配上相关的LaTeX公式。 这些技术都是当前大型语言模型&#xff08;LLM&#xff09;领域为了提升模型性能、训练效率、推理速度或稳定性而采用的关键组件。 1. Grouped Query Attention (GQA) - 分组…...

【慧游鲁博】【8】前后端用户信息管理:用户基本信息在小程序端的持久化与随时获取

文章目录 本次更新整体流程概述1. 用户登录流程前端登录处理 (login.vue)后端登录处理 (AuthServiceImpl.java) 2. 用户信息存储机制前端状态管理 (member.js) 3. 后续请求的身份验证登录拦截器 (LoginInterceptor.java)前端请求携带token 4. 获取用户信息获取用户信息接口 (Us…...

上位机知识篇---keil IDE操作

文章目录 前言文件操作按键新建打开保存保存所有编辑操作按键撤销恢复复制粘贴剪切全选查找书签操作按键添加书签跳转到上一个书签跳转到下一个书签清空所有书签编译操作按键编译当前文件构建目标文件重新构建调试操作按键进入调试模式复位全速运行停止运行单步调试逐行调试跳出…...

Odoo: Owl Hooks 深度解析技术指南

你好&#xff01;作为一名 Odoo 开发者&#xff0c;深入理解其前端框架 Owl.js&#xff0c;尤其是 Hooks&#xff0c;是提升开发效率和代码质量的关键。这份指南将带你从基础概念到高级应用&#xff0c;全面掌握 Odoo 18 中 Owl Hooks 的所有知识点。 1. Hooks 核心概念介绍 什…...

SpringBoot返回xml

默认情况下引入web依赖后自带了JackJson 返回JSON数据 你也可以引入fastJSON 那么方便使用可以用JSON.xxx 如果希望Boot默认返回xml数据 <dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml<…...

【案例篇】 实现简单SSM工程-后端

简介 本篇文章将带你从0到1的实现一个SSM项目&#xff0c;通过此案例可以让你在项目中对SpringBoot的使用有一个更加详细的认识&#xff0c;希望这个简单的案例能够帮到你。文章内容若存在错误或需改进的地方&#xff0c;欢迎大家指正&#xff01;若对操作有任何疑问欢迎留言&a…...

零基础学习计算机网络编程----网络基本知识

目录 1. 计算机网络发展 1.1 网络发展 1.2 媒介 2 认识协议 2.1 为什么要有协议 2.2 协议的本质 3 网络协议的初识 3.1 什么是协议分层 3.2 为什么会有 4. OSI七层模型 4.1 定义 5. TCP/IP五层(或四层)模型 5.1 有什么 6. 网络传输基本流程 6.1 网络传输流程图…...

Zynq和Microblaze的区别和优势

Zynq芯片包含了一颗双核ARM Cortex-A9处理器&#xff0c;这是一颗“硬”处理器---它是芯片上专用 而且优化过的硅片原件。 MicroBlaze为“软”处理器&#xff0c;它是由可编程逻辑部分的单元组合而成的&#xff0c; 也就是说&#xff0c;一个 软处理器的实现和部署在FPGA的逻…...

FastAPI 支持文件下载

FastAPI 支持文件下载 FastAPI 支持文件上传 Python 获取文件类型 mimetype 文章目录 1. 服务端处理1.1. 下载小文件1.2. 下载大文件&#xff08;yield 支持预览的&#xff09;1.3. 下载大文件&#xff08;bytes&#xff09;1.4. 提供静态文件服务 2. 客户端处理2.1. 普通下载2…...

CNN卷积神经网络到底卷了啥?

参考视频&#xff1a;卷积神经网络&#xff08;CNN&#xff09;到底卷了啥&#xff1f;8分钟带你快速了解&#xff01; 我们知道&#xff1a; 图片是由像素点构成&#xff0c;即最终的成像效果是由背后像素的颜色数值所决定 在Excel中&#xff1a;有这样一个由数值0和1组成的66…...

vue中v-clock指令

基础 v-cloak 是 Vue 中的一个非常实用的指令&#xff0c;用于防止在 Vue 实例尚未挂载完成前&#xff0c;用户看到模板中的插值语法&#xff08;如 {{ message }}&#xff09;一闪而过。 ✅ 场景举例 你在页面还没加载完前&#xff0c;可能会看到这样一瞬间的内容&#xff…...

MIT 6.S081 2020Lab5 lazy page allocation 个人全流程

文章目录 零、写在前面一、Eliminate allocation from sbrk()1.1 说明1.2 实现 二、Lazy allocation2.1 说明2.2 实现 三、Lazytests and Usertests3.1 说明3.2 实现3.2.1 lazytests3.2.2 usertests 零、写在前面 可以阅读下4.6页面错误异常 像应用程序申请内存&#xff0c;内…...

C++初阶-list的使用2

目录 1.std::list::splice的使用 2.std::list::remove和std::list::remove_if的使用 2.1remove_if函数的简单介绍 基本用法 函数原型 使用函数对象作为谓词 使用普通函数作为谓词 注意事项 复杂对象示例 2.2remove与remove_if的简单使用 3.std::list::unique的使用 …...

PHP序列化数据格式详解

PHP序列化数据格式详解 概述 PHP序列化是将PHP变量&#xff08;包括对象&#xff09;转换为可存储或传输的字符串表示形式的过程。了解这些序列化格式对于数据处理、调试和安全性分析非常重要。本文将详细介绍PHP中各种数据类型的序列化表示方式。 基本数据类型序列化格式 …...

如何优化 MySQL 存储过程的性能?

文章目录 1. 优化 SQL 语句避免全表扫描减少子查询&#xff0c;改用 JOIN避免 SELECT 2. 合理使用索引3. 优化存储过程结构减少循环和临时变量避免重复计算 4. 使用临时表和缓存5. 优化事务处理6. 分析和监控性能7. 优化数据库配置8. 避免用户自定义函数&#xff08;UDF&#…...

深度学习:损失函数与激活函数全解析

目录 深度学习中常见的损失函数和激活函数详解引言一、损失函数详解1.1 损失函数的作用与分类1.2 回归任务损失函数1.2.1 均方误差&#xff08;MSE&#xff09;1.2.2 平均绝对误差&#xff08;MAE&#xff09; 1.3 分类任务损失函数1.3.1 交叉熵损失&#xff08;Cross-Entropy&…...

【大前端】Node Js下载文件

NodeJs 获取远程文件有很多方式&#xff0c;常见的方式有以下两种&#xff1a; - fetch&#xff08;原生&#xff09; - axios&#xff08;插件&#xff09; 通过 Fetch 下载文件&#xff0c;代码如下&#xff1a; import fs from node:fsfunction main(){fetch(http://xxx.x…...

自训练NL-SQL模型

使用T5小模型在笔记本上训练 nature language to SQL/自然语言 转SQL 实测通过。 本文介绍了如何在笔记本上使用T5小模型训练自然语言转SQL的任务。主要内容包括:1) 创建Python 3.9环境并安装必要的依赖包;2) 通过Hugging Face镜像下载wikisql数据集和T5-small模型;3) 实现…...