软件测试——03 单元测试与集成测试
1 单元测试
1.1 简介
- 核心定义:明确单元测试聚焦软件 “基本组成单元”(像函数、类 、模块等),且要 “独立测试”,不依赖其他模块,精准验证单个单元逻辑;
- 实施时机:常规是和编码同步,保证开发中及时验证;TDD(测试驱动开发)模式更激进,要求先写测试用例,再编码实现,倒逼代码贴合需求、易测试;
- 执行主体:强调 “开发人员完成”,因开发最懂单元逻辑,能高效设计测试、排查问题,是保障代码质量的基础环节。
1.2 为什么要进行单元测试?
- 早发现、低成本解决问题:
- 单元测试能在开发早期(代码刚写完时)揪出错误。因为此时问题就聚焦在单个单元(比如函数、类),定位快、修复简单;
- 要是等系统集成后才发现,问题会嵌套在复杂逻辑里,排查和修复成本(时间、人力、对其他功能的影响)会大幅飙升;
- 保障代码质量,方便长期维护:
- 通过单元测试,能验证代码是否符合最初的设计思路、编码规范(像命名、注释、逻辑结构);
- 规范且贴合设计的代码,后续别人接手、迭代功能时,更容易理解和修改,减少 “维护噩梦” 。
1.3 单元测试的目标
- 单元测试目标是检验单元模块编码与软件系统设计的一致性,需验证的内容如下:
- 数据流入流出单元是否正常;
- 在单元工作过程中,其内部数据(形式、内容、关系等)是否完整,全局变量处理是否得当;
- 数据加工边界(比如临界值)是否能正确工作;
- 单元运行是否覆盖特定逻辑(像分支、条件覆盖);
- 错误处理是否有效(出错了能不能合理反馈、恢复);
- 指针、资源(比如内存)是否正确管理;
- 有无安全隐患(比如字符串处理是否有漏洞)。
1.4 单元测试的关注内容
- 目标:检验各单元模块是否被正确地编码;
- 依据:《软件详细设计说明书》和《软件需求规格说明书》;
- 过程:设计、脚本开发、执行、调试和分析结果;
- 执行者:程序开发人员和测试人员;
- 测试方法:代码控制流和数据流分析法,并结合参数输入域;
- 测试脚本管理:记录代码评审、版本分支、变更控制等;
- 评估:代码覆盖率。
1.5 通过单元测试的一般准则
- 软件单元功能与设计需求一致;
- 软件单元接口与设计一致;
- 能够正确处理输入和运行中的错误;
- 在单元测试中发现的错误已经得到修改并且通过了测试;
- 达到了相关的覆盖率的要求;
- 完成软件单元测试报告。
1.6 单元测试的 5 类具体任务
- 任务 1:模块独立执行路径测试
- 目标:覆盖模块所有独立执行流程,保证每条语句至少跑一次(即 “语句覆盖”),别让隐藏逻辑出错;
- Checklist:
- 误解或用错了算符优先级(像
a + b * c写成(a + b) * c) - 混合类型运算(如字符串和数字直接运算)
- 变量初值错误、赋值错误(没初始化就用,或把
=写成==) - 错误计算或精度不够表达式符号错(小数运算误差)
- ……
- 误解或用错了算符优先级(像
- 任务 2:局部数据结构测试
- 目标:检查模块内局部数据结构是否完整、正确,避免因数据基础问题引发错误;
- Checklist:
- 不适合或不相容的类型说明(用字符串存数字,却按数值运算)
- 变量无初值
- 变量初始化或默认值有错
- 不正确的变量名或从来未被使用过
- 出现上溢或下溢和地址异常(数组越界、数值超出类型范围)
- ……
- 任务 3:模块接口测试
- 目标:验证模块间交互的 “接口” 是否正确,保证模块能正常协同工作;
- Checklist:聚焦参数、全局变量、外部交互:
- 输入的实际参数与形式参数是否一致(个数、属性、单位)
- 调用其他模块的实际参数与被调模块的形参是否一致
- 全局变量的定义在各模块是否一致
- 外部输入、输出
- 文件、缓冲区、错误处理
- ……
- 任务 4:单元边界条件测试
- 目标:验证代码在 “边界值” 场景下的处理是否正确,因为边界往往是 Bug 高发区;
- Checklist:分 4 类场景:
- 普通合法数据的处理
- 普通非法数据的处理
- 边界值内合法边界数据的处理
- 边界值外非法边界数据的处理
- ……
- 任务 5:单元容错测试
- 目标:确保模块出错时,预设的错误处理机制(比如报错提示、异常捕获)有效,别让小错误拖垮整个程序;
- Checklist:关注错误处理的质量:
- 报错信息要清晰:别抛 “未知错误”,得让开发 / 用户知道哪错了(比如 “数据库连接超时,请检查网络”)
- 错误记录要准:日志里记的错误,得和实际问题对得上,方便排查
- 异常处理得当:别因为一个小异常(比如除数为 0)就让程序崩溃,得有兜底逻辑(比如返回默认值、提示重试)
- 定位信息要足:报错时,得带上代码位置、参数值等,帮开发快速定位问题
2 静态测试
2.1 定义
- 定义:不运行程序,通过 “人工检查、阅读代码” 分析问题。比如代码写完后,开发或测试人员直接看代码,找语法错误、逻辑漏洞,像放大镜一样 “静态” 排查问题,不用实际跑程序。
2.2 编码的标准和规范
- 标准:必须遵守的 “硬规则”(比如 Java 规定变量命名不能用关键字);
- 规范:推荐的 “最佳实践”(比如函数长度别太长,代码要加注释);
- 实施原因:
- 可靠性:按标准写,代码逻辑更稳,少出 Bug;
- 可读性 & 可维护性:规范的代码,别人(或未来的你)读得懂、改得动;
- 可移植性:符合标准,代码在不同环境(比如换服务器)也能跑,减少适配成本。
2.3 代码评审(Code Review)
- 价值:能发现代码中 60% 以上的缺陷!通过互查、走查、会议评审等形式,提前揪出问题。
- 实操要点:
- 一次查 200 - 400 行代码,别超过 60 - 90 分钟(太久会疲劳,漏问题);
- 速度建议 300 - 500 行 / 小时,别太快 / 太慢;
- 量化目标(比如 “每次评审发现 X 个 Bug”),持续优化流程;
- 评审前,代码作者要加注释,方便别人理解逻辑;
- 用 “检查表”(列好要查的点,比如是否符合编码规范)提高效率;
- 改完 Bug 要验证,确保真的修复了。
2.4 走查(Walk Through)
- 定义:用 “讲解、讨论、模拟运行” 的方式找错误。比如开发人员聚在一起,作者讲解代码逻辑,大家一起模拟程序跑的过程,找问题;
- 注意事项:
- 走查前,成员要通读设计和代码,别啥都不懂就开会;
- 限时!别跑题(比如聊到需求变更,就偏离 “查代码” 了);
- 发现问题先记录,别现场改(越改越乱,会后统一处理);
- 重点查:是否符合编码规范、有没有逻辑错误(比如条件判断写反)。
2.5 审查(Inspection)
- 定义:更正式的 “会议评审”,按流程、规则来查问题;
- 流程 & 要求:
- 会前准备:定目标、流程、规则(比如谁主讲、查哪些点);
- 用 “缺陷检查表” 逐项查(比如列好 “是否有空指针风险”“变量是否初始化”);
- 发现问题先记录,别现场改;如果有重大缺陷,改完得重新开审查会,确保问题真的解决。
2.6 走查 VS 审查
| 走查 | 审查 | |
|---|---|---|
| 准备 | 通读设计和编码 | 事先准备 Spec、程序设计文档、源代码清单、代码缺陷检查表等 |
| 形式 | 非正式会议 | 正式会议 |
| 参加人员 | 开发人员为主 | 项目组成员包括测试人员 |
| 主要技术方法 | 无 | 缺陷检查表 |
| 生成文档 | 会议记录 | 静态分析错误报告 |
| 目标 | 代码标准规范、无逻辑错误 | 代码标准规范、无逻辑错误 |
3 动态测试
3.1 简介
- 核心特点:必须运行程序,通过设计测试用例,验证程序功能是否符合预期。和 “静态测试(不运行程序,纯看代码)” 完全不同;
- 关键步骤:
- 设计测试用例:想清楚要测哪些场景(比如正常输入、异常输入),写具体的测试数据和操作步骤;
- 编写驱动程序 + 桩程序:因为单元测试的模块(比如一个函数)往往不是 “独立可运行的程序”,得用辅助模块模拟它的 “上下游依赖”(比如调用它的模块、它调用的其他模块);
- 执行测试 & 记录结果:跑程序,看实际输出是否和预期一致,记录问题。
3.2 驱动程序和桩程序
-
因为单元测试的模块不是独立程序,得处理 “谁调用它”“它调用谁” 的问题,所以需要这两种辅助模块:

类型 作用 场景举例 驱动模块(drive) 模拟 “调用被测模块的上层模块”,给被测模块传参、触发它执行 测试一个 “计算工资” 的函数,驱动模块负责传员工考勤、绩效等数据,让函数跑起来 桩模块(stub) 模拟 “被测模块调用的下层模块”,返回预设结果,替代真实依赖(比如数据库、其他函数) 被测函数需要调用 “查询员工信息” 的接口,用桩模块直接返回假的员工信息,避免依赖真实接口 -
驱动模块:负责 “推动” 被测单元执行(传参、触发);
-
桩模块:负责 “接住” 被测单元的依赖(比如被测单元要调其他模块,桩模块冒充它们返回数据)。
3.3 实例1:小张负责 B 模块的测试(模块依赖场景)
- 背景:
- 任务分工:7 个人各做一个模块,小张做 B 模块,现在要测 B,但 B 不是顶层模块(顶层 A 有 main 函数),还依赖 D、E 模块(D、E 还没开发好);
- 问题:B 不能独立运行(没 main 函数启动),也没法编译(依赖的 D、E 没做好),咋测?
- 解决(驱动 + 桩的实践):
- 解决 “无法编译” 问题 → 用桩模块(Sd、Se):
- 因为 B 调用了 D、E ,但 D、E 没开发好,所以写桩模块 Sd(代替 D)、Se(代替 E);
- 桩模块的作用:假装自己是 D、E,让 B 能通过编译(函数名、返回值、参数和真实 D、E 一样,但逻辑很简单,比如直接返回固定值);
- 解决 “无法独立运行” 问题 → 用驱动模块(Da):
- B 不是顶层模块(没 main 函数 ),所以写驱动模块 Da(代替 A);
- 驱动模块的作用:包含 main 函数,在 main 里调用 B ,让 B 能跑起来,模拟 A 模块调用 B 的过程。
- 解决 “无法编译” 问题 → 用桩模块(Sd、Se):
3.4 实例2:大型网络服务系统的测试(复杂场景扩展)
- 背景:
- 测试对象:多台数据库服务器的数据服务模块(被测试单元);
- 难点:模块依赖网络环境、服务器环境,还涉及多模块交互,咋测?
- 解决(驱动程序的复杂应用):
- 驱动程序的作用:
- 模拟 “调用被测试单元” 的场景,同时模拟 “被测试单元调用的其他模块”;
- 比如:驱动程序在服务器端运行,模拟数据库收发数据,既能发数据包(当调用方),又能收数据包(当被调用方),相当于 “既是驱动,又兼职桩”;
- 测试用例设计(覆盖复杂场景 ):
- 测性能:不同数据包大小(大包低频、小包高频);
- 测交互:两个驱动程序互发数据,模拟多模块通信;
- 测扩展性:多个驱动程序、跨网段(模拟真实环境的复杂网络)。
- 驱动程序的作用:
3.5 类测试
- 类的单元测试:聚焦类的成员函数(比如 Java 里的
public void add()),测试单个函数的逻辑是否正确; - 类测试:更宏观,验证整个类的实现是否和设计说明一致。不仅看函数,还要看类的属性、函数间协作、整体功能是否符合需求;
- 类测试的难点:多态和继承
- 多态:同一方法,不同子类有不同实现(比如父类
Animal有speak(),子类Dog实现 “汪汪”、Cat实现 “喵喵”)。测试时要覆盖所有子类的不同行为,避免遗漏; - 继承:子类会继承父类的属性和方法,还可能重写。测试时要考虑 “父类逻辑 + 子类重写逻辑” 的组合,防止继承带来的隐藏问题(比如子类重写方法时,破坏了父类的约束);
- 多态:同一方法,不同子类有不同实现(比如父类
- 展平测试(应对继承复杂场景的方法)
- 核心思路:把子类自身的成员(方法 + 变量) + 父类继承来的成员(方法 + 变量),合并成一个 “新类” 来测试;
- 作用:避免继承关系带来的测试遗漏。比如直接测子类时,可能忽略父类逻辑的影响;展平后,相当于把父类和子类 “拍平” 成一个整体,一次性验证所有继承相关的功能是否正确。
3.6 案例分析
-
空指针保护案例分析
-
用户输入用户名,代码获取后判断是否为管理员,但没处理“用户名为空”的情况,会导致空指针异常(
userName为null时,调用equals直接报错);/** * 通过用户UI界面输入的用户名,传递到Action层,进行用户角色识别操作 * * @param request HttpServletRequest * * @return String 用户角色,像管理员/普通用户/... */ public String getUserRole(HttpServletRequest request) { String userRole = ""; String userName = request.getParameter("userName"); if (userName.equals("schadmin")) { //这是系统初始化时默认的管理员账号,如果是,则做以下的验证操作...... } //非系统初始化的账号,做以下验证操作...... return userRole; } -
当
request.getParameter("userName")返回null(比如前端没传这个参数),执行userName.equals(...)会抛出NullPointerException; -
修复建议:先判空,再调用方法,比如
if ("schadmin".equals(userName))(常量放前面,避免空指针),或者先判断userName != null;
-
-
格式化数字错误案例分析
-
将用户输入的年龄(字符串)转成数字,但没处理 “输入不是合法数字” 的情况,会导致
NumberFormatException(比如用户输入字母);/** * 通过用户输入的年龄,转换为数值型 * * @param request HttpServletRequest * * @return Integer 用户年龄 */ public int getUserAge(HttpServletRequest request) { int age = 0; String userAge = request.getParameter("userAge"); if (userAge != null) { age = Integer.parseInt(userAge); } return age; } -
如果
userAge是null,代码逻辑会返回0(没问题);但如果userAge是非数字字符串(比如"abc"),Integer.parseInt会抛异常,程序崩溃; -
修复建议:增加异常捕获,或者用
try-catch处理,比如:if (userAge != null) { try { age = Integer.parseInt(userAge); } catch (NumberFormatException e) { // 处理异常,比如返回默认值、记录日志 age = 0; } }
-
-
字符串或数组越界案例分析
-
按逗号拆分电话号码字符串,直接取第 3 个元素(索引 2),但没处理 “数组长度不足 3” 的情况,会导致数组越界异常;
/** * 假设电话号码字串设计的标准格式为:国家编码-区位号码-电话号码-分机号 * 举例如86,0551,2313222,8093 * * @param strPhoneNumber String * * @return String 电话号码(如:例子中的2313222) */ public static String getPhoneNumber(String strPhoneNumber) { if ((strPhoneNumber == null) || "".equals(strPhoneNumber)) { return ""; } String[] arrPhone = strPhoneNumber.split(","); return arrPhone[2]; } -
如果输入的
strPhoneNumber拆分后数组长度小于 3(比如"86,0551"),arrPhone[2]会抛出ArrayIndexOutOfBoundsException; -
修复建议:增加数组长度判断,比如:
if (arrPhone.length > 2) { return arrPhone[2]; } else { // 处理异常,返回默认值或报错 return ""; }
-
-
其它示例:
- Error404 / 500:页面找不到、服务器内部错误,通常是路由配置错、代码抛未处理异常;
- 资源未关闭:比如数据库连接、文件流用完没关,导致资源泄漏,系统性能下降甚至崩溃;
- 不当使用 synchronized:多线程场景下,过度或错误加锁,导致性能瓶颈(比如锁粒度太粗)、死锁;
- 调用不当方法:比如调用了过时方法、参数传错,导致结果异常。
3.7 分层单元测试
-
分层测试的意义:Web 应用通常分多层(比如 Action 层处理请求、数据访问层操作数据库、Servlet 处理 HTTP 交互)。分层测试能精准验证每层的逻辑,避免层级间依赖干扰,让问题定位更简单;
-
测试对象:
- Action 层:处理业务流程、调用其他模块的层级;
- 数据访问层:直接操作数据库(增删改查)的层级;
- Servlet:处理 HTTP 请求 / 响应的 Java 组件;
-
Action 层的单元测试:
- Action 层会依赖其他对象(比如 Service、DAO),直接测试会受这些依赖影响;
- 解决方案:Mock 技术
- Mock 的作用:模拟 Action 层依赖的对象和数据,让 Action 层能 “独立运行”。比如假装调用了 Service 方法,返回预设结果,测试 Action 层的逻辑是否正确处理这个结果;
- StrutsTestCase 工具:基于 JUnit 扩展,专门给 Struts 框架的 Action 做测试。帮你模拟 Struts 环境(比如请求、会话),不用启动整个 Web 应用就能测 Action;
-
Biz 逻辑事务层的单元测试
- Biz 层(业务逻辑层)通常操作数据库,测试时要隔离外部依赖(比如真实数据库),否则测试结果会受数据库状态影响(比如测试后数据被修改,下次测试就不准了);
- 解决方案:DbUnit
- DbUnit 的作用:控制测试数据库的状态。比如测试前,初始化数据库数据(插入固定测试数据);测试后,恢复数据库到测试前状态(避免影响其他测试);
- 优势:让 Biz 层测试更稳定、可重复。不管数据库原本啥样,测试时都用预设数据,结果更可靠;
-
Servlet 的单元测试
- Servlet 依赖 Servlet 容器(比如 Tomcat)才能运行,直接测试需要部署应用,很麻烦;
- 解决方案:HttpUnit
- HttpUnit 的作用:模拟 Servlet 容器环境,让 Servlet 不用部署到 Tomcat 就能测试。你可以模拟 HTTP 请求(GET、POST),直接调用 Servlet 的逻辑,看响应是否符合预期;
- 实操步骤:
- 用
ServletRunner模拟容器环境; - 单个 Servlet 测试:用
registerServlet注册,直接调用; - 多个 Servlet 测试:写
web.xml配置,传给ServletRunner构造器,模拟真实应用的 Servlet 配置。
- 用
3.8 示例:单元测试检查表
- 关键测试项是否已纠正
- 有无任何输入参数没有使用?有无任何输出参数没有产生?
- 有无任何数据类型不正确或不一致?
- 有无任何算法与 PDL 或功能需求中的描述不一致?
- 有无任何局部变量使用前没有初始化?
- 有无任何外部接口编码错误?即调用语句、文件存取、数据库错误
- 有无任何逻辑路径错误?
- 该单元是否有多个入口或多个正常的出口?
- 额外测试项
- 该单元中有任何地方与 PDL 与 PROLOG 中的描述不一致?
- 代码中有无任何偏离本项目标准的地方?
- 代码中有无任何对于用户来说不清楚的错误提示信息?
- 如果该单元是设计为可重用的,代码中是有可能妨碍重用的地方?
4 集成测试
4.1 系统集成的模式与方法
- 集成测试:把多个模块 / 组件拼起来,验证它们协同工作是否正常;
- 集成测试的模式:比如 “自顶向下”“自底向上” 等不同集成顺序;
- 持续集成:频繁(比如每次代码提交 )自动集成、测试,提前发现集成问题(DevOps 里的关键实践)。
4.2 为什么总是集成不起来?
-
本质问题:单独模块测好后,拼在一起可能因为 “模块间交互” 出问题;
- 模块像铁轨,拼接时可能因为接口、功能冲突等,导致整体 “接不通”;

-
具体原因:
- 数据丢失:模块接口传数据时,格式、内容不匹配,导致数据丢了(比如 A 模块传字符串,B 模块按数字解析);
- 功能组合失败:单个模块功能正常,但组合后达不到整体需求(比如购物车模块 + 支付模块,一起用时报错);
- 模块相互影响:一个模块的功能(比如修改全局变量),干扰另一个模块的逻辑;
- 全局数据问题:全局变量、配置不一致,导致集成后逻辑混乱;
- 误差积累:单个模块的小误差,集成后被放大(比如计算模块精度丢失,多个模块调用后结果偏差巨大);
4.3 集成测试优势
- 核心价值:解决 “模块单独好、集成就崩” 的问题,从系统层面验证功能。具体优势:
- 检查环境配置:比如数据库、接口、缓存的配置是否正确(很多系统崩溃是因为配置不对);
- 模拟真实业务:把多个模块串起来,模拟用户实际操作流程(比单个模块测试更贴近真实场景);
- 快速定位 Bug:集成测试发现的问题,能更快锁定是 “模块间交互” 导致的,减少排查时间;
- 支撑功能 / 性能测试:集成测试通过后,再做全系统的功能、性能测试更有效;
- 类比理解:
- 接口测试像 “检查每个铁路零件(铁轨、螺丝)是否合格”;
- 集成测试像 “把铁轨拼起来,看整条铁路是否能通火车”,更贴近用户实际使用的 “完整流程”。
4.4 集成测试的模式
4.4.1 两种基本模式
- 非渐增式(大棒模式):
- 做法:先单独测每个模块(单元测试),然后一次性把所有模块拼起来测;
- 缺点:一旦出问题,很难定位是哪个模块的问题(因为所有模块一起集成,报错后像 “大棒打下来,找不到具体原因”);
- 适用场景:只有模块少、系统简单时才用(实际开发很少用,除非项目特别小);
- 渐增式:
- 做法:每次只加一个新模块到已测好的模块里,测完再继续加下一个;
- 优点:出问题能快速定位(因为每次只加一个模块,报错就是新模块或它和现有模块的交互问题);
- 衍生出 “自顶向下”“自底向上”“混合策略” 等具体方法。
4.4.2 大棒集成方法
-
流程:单元测试→所有模块一次性集成→集成测试;
-
问题:如图里的模块 A、B、C…,单独测好后,一次性拼起来。如果报错,可能是 B 和 E 交互错、D 和 G 交互错…很难快速找到具体哪个模块或接口的问题;

-
总结:简单项目能用,但稍微复杂的系统,不推荐(定位问题太麻烦)。
4.4.3 自顶向下集成
-
思路:从最顶层的模块(比如系统入口、主流程模块)开始,用桩模块代替下层未测模块,测完顶层,再逐步替换桩模块为真实模块,往下集成;

-
两种顺序(深度优先 vs 宽度优先):

- 深度优先:比如先测 M1→M2→M5→M8(一路往下钻),再测其他分支;
- 宽度优先:比如先测 M1→M2→M3→S4(同一层横向测),再测下一层;
-
优点:能先验证主流程(顶层模块通常是核心流程), early 发现流程问题;
-
缺点:需要写很多桩模块(模拟下层未测模块),如果下层逻辑复杂,桩模块可能很难写。
4.4.4 自底向上集成
-
思路:从最底层的模块(比如数据库操作、工具类)开始,用驱动模块调用这些模块,测完底层,再逐步往上集成上层模块;

-
“族” 的概念:把底层功能相关的模块组成 “族”,先测族内集成,再把族当整体往上拼;
-
优点:不需要写桩模块(因为底层模块依赖少,用驱动模块直接调),适合底层逻辑复杂的系统(比如大量数据库操作);
-
缺点:主流程(顶层)的问题会很晚才发现(因为最后才集成上层)。
4.4.5 混合策略(自顶向下 + 自底向上)
- 思路:上层模块用 “自顶向下” 测(先主流程),下层模块用 “自底向上” 测(先底层功能),中间会师;
- 优点:结合两者长处,既早验证主流程,又早验证底层功能,减少桩模块和驱动模块的编写量。
4.4.6 三明治集成(改进版混合策略)
- 基础三明治:自顶向下 + 自底向上,从两头往中间集成,不需要写桩模块(因为底层先测好,顶层调用时用真实模块);
- 问题:模块可能没单独测过,集成前风险没暴露;
- 再次改进:集成前,每个模块先单独测,再两头往中间集成。这样既保证模块独立正确,又高效集成。
4.5 持续集成
-
简介:
- 是什么:一种开发实践,要求团队成员频繁集成代码(通常每天至少 1 次,甚至多次);
- 比如:小明改了用户登录功能,小红改了购物车功能,两人每天下班前把代码合并到主干,而不是等 weeks 后再集成。
- 为什么好:
- 早发现 Bug:集成越频繁,每次合并的代码越少,出问题时容易定位(比如今天只改了登录,集成报错就优先查登录逻辑);
- 避免 “集成地狱”:如果很久不集成,大量模块堆积,最后合并时会有无数冲突和 Bug,修复成本极高;
- 是什么:一种开发实践,要求团队成员频繁集成代码(通常每天至少 1 次,甚至多次);
-
持续集成的实践流程
-
持续集成不是 “只合并代码”,而是一套自动化流程,确保每次集成的代码是 “可工作的”;
-
关键步骤:
步骤 作用 举例 定期提交代码 约束开发节奏,避免一人改太多代码,导致集成困难 每天下班前提交,或按功能分支小步提交 自动代码静态测试 不运行代码,检查语法、规范(比如变量未使用、代码格式错) 用 SonarQube 扫代码异味 自动单元动态测试 运行单元测试,验证模块逻辑是否正确 JUnit 测单个函数逻辑 自动构建包验证(BVT) 把代码打包、部署到测试环境,验证 “能不能跑起来”(比如依赖是否缺失) Maven 打包,Docker 部署 自动部署 部署到测试环境,模拟真实运行场景 部署到测试服务器 自动生成测试报告 汇总测试结果,方便快速看 “这次集成是否通过” Jenkins 生成报告
-
-
持续集成的价值
- 对开发:不用等到最后才集成,每天小步合并,冲突少、Bug 好修;
- 对测试:自动化测试覆盖基本场景,减少重复人工测试,能更早介入找问题;
- 对项目:持续保障代码可运行,随时能交付,避免 “最后冲刺发现大量问题” 的风险。
更多推荐
所有评论(0)