跳到主要内容
QZ Site
首页写作项目关于

© 2026 QZ Site. All rights reserved.

豫ICP备2026034998号-1|琼公网安备46020002000486号

← 返回写作

项目上线前,到底要做哪些测试?

测试·2026年8月5日·26 分钟阅读

本地能跑、构建成功,只回答了很小一部分问题。真正准备上线时,还要知道:规则有没有算错,模块接起来会不会丢数据,用户能否完成操作,流量上来后是否撑得住,权限与部署配置会不会泄露信息,以及出问题后能不能恢复。

测试应该围绕这些风险安排,而不是临上线才把工具名单跑一遍。下面用一个 Next.js 博客的发文功能串起开发、合并、预发布和上线后的工作。它是说明方法的例子,不是本站已经完成测试的报告;文中没有本站的压测成绩或安全结论。

1 先把测试名称放回各自的维度

观点

“单元、黑盒、回归、自动化”可以同时形容一个测试,并不是四选一。

你想说明什么对应概念
测多大的对象单元测试看函数或组件;集成测试看协作边界;系统测试看完整系统
是否满足交付要求验收测试依据业务与使用方认可的验收条件
是否走完整条路径E2E 从用户入口走到最终结果,可能跨越多个系统
这次重点防什么功能正确性、性能、安全等;回归关注变更是否破坏已有行为
用什么依据设计用例黑盒依据外部行为约定;白盒依据内部结构;灰盒结合部分内部信息
怎样执行手工、自动化,或两者结合

系统测试可以包含 E2E,也可以通过 API 验证系统行为;一个 E2E 用例可以承担验收或回归任务。验收重在业务条件是否满足,不等于“浏览器脚本跑完”。这些概念有交叉,不需要再排成一条单向升级路线。测试层级与设计技术的基本区分可参照 ISTQB CTFL 大纲。

对发文功能,先写几个具体风险就够开始:中文标题生成空地址;重复提交写出两篇文章;保存成功但刷新后内容消失;未登录访客读到草稿;发布后页面在目标流量下变慢。每个风险都要对应一个可观察的预期结果。

2 开发时 先验证规则和模块之间的约定

单元测试把边界说清楚

单元测试通常隔离一个函数或组件,反馈快,适合覆盖业务规则、分支和边界。开发时就写,重构后继续跑;不必机械地给每个没有独立逻辑的包装函数凑一条测试。

例如,先规定这个演示用 slug 函数只保留 ASCII 字母和数字,其他连续字符转成连字符。它不负责中文转拼音,也不代表所有博客都应该采用这个规则。

slug.test.mjsjavascript
// 独立演示,可保存为 slug.test.mjs 后用 node --test 运行。
import test from 'node:test';
import assert from 'node:assert/strict';

function slugify(title) {
  return title.toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '');
}

for (const [input, expected] of [
  ['Hello World', 'hello-world'],
  ['React 入门指南', 'react'],
  ['  A---B  ', 'a-b'],
  ['中文标题', ''],
]) {
  test(JSON.stringify(input), () => {
    assert.equal(slugify(input), expected);
  });
}

最后一项尤其重要:函数按约定返回空字符串,不代表发文系统可以接受空地址。调用方还要选择拒绝、允许自填 slug,或生成稳定的替代值,并测试这个业务决定。测试能为这些已覆盖场景是否符合约定提供证据,也可能暴露约定本身不够用。

集成测试验证真实连接处

文章 API 与数据库接起来后,就可以做集成测试,无须等到“开发后期”。关注请求字段、鉴权上下文、数据库约束、事务与返回结果是否一致。

以 POST /api/posts 为例,测试安排可以很短:

text
准备:隔离测试数据库、测试账号、唯一的测试标识
操作:提交一篇文章
断言:响应符合接口约定;按返回的 ID 查库,标题和正文一致
补测:重复 slug、重复提交、无权限、数据库写入失败
清理:删除本例数据,保证用例不依赖运行顺序

创建成功返回 201 还是项目约定的其他成功状态,应由接口契约决定;只断言 200 或“记录不为空”,容易漏掉写错内容、写了两次等问题。内存 mock 能验证调用逻辑,但不能代替真实数据库对唯一约束、事务和并发冲突的验证。使用真实数据库时,必须与生产数据隔离。

比如两个请求几乎同时创建同一个 slug,应用层的“先查是否存在”可能都得到不存在。测试要检查数据库唯一约束是否兜住冲突,以及应用能否返回约定的错误,而不只是让其中一个请求报出未处理异常。

白盒与黑盒决定怎样补用例

看实现时,可以沿语句、分支和数据流找遗漏;看需求时,可以从边界值、状态变化和用户可见结果反推用例。两种设计思路互补,都能用于运行中的程序,也都可能用于功能或安全测试。

例如,代码审查发现递归缺少终止或深度保护、深度过大可能导致栈溢出,或 Map 缓存没有清理过期项、重复定义覆盖了原逻辑、输入校验不完整或数据库缺少唯一约束,应再补相应测试。React 的服务端与客户端首屏输出不一致,也要结合渲染结果和浏览器信息验证 hydration 风险。审查与静态分析不运行被测程序,不能直接等同于白盒测试;这些缺陷也并非只能从内部发现。

黑盒依据约定检查外部行为,不要求测试者必须是攻击者,也不要求具备攻击经验。灰盒则使用部分内部信息,例如已知架构和部分日志;仅做公开信息收集(OSINT),不能自动称为灰盒。内部视角有利于定位,但受结构与场景覆盖限制;外部视角贴近行为要求,但观测和根因定位有限。两者都需要持续做,成本取决于范围、理解程度和工具。

3 合并前 让变化不会悄悄破坏旧功能

回归测试关注的是变化的影响,可以由单元、集成、系统或 E2E 用例共同承担。修复一个 bug 后,先用对应场景确认修复,再检查邻近行为是否被破坏。例如修改 slug 生成规则,除了新文章,还要考虑已有文章地址、编辑保存和重复标题。

CI(持续集成)把这些检查变成稳定的合并反馈。以 GitHub Actions 为例,可以在 push、pull_request 时检出代码,设置项目支持的 Node.js 版本,再执行:

bash
npm ci
npm run lint
npm test
npm run build

这些命令需要项目已有锁文件和对应脚本;npm test 是否包含集成测试、是否会退出而非进入 watch 模式,都要核对。E2E 若是独立脚本,就要显式加入,不会自动发生。应通过分支保护或规则集将必要 CI 检查设为合并门槛,部署任务也明确依赖检查结果,并保留对应 commit 的日志与报告。GitHub Node.js 构建与测试文档

小项目可以每次运行全部已有测试;测试集增长后,可按变更风险分层执行,把较慢的完整测试安排在发布前或定时任务。必须说明本次实际跑了什么,不能把“CI 绿了”写成“所有环境都验证过”。通过只表示在指定版本、环境、输入和用例范围内没有观察到问题。

手工与自动化也不是按测试名称分家的。单元、集成、E2E 都能自动化;人工探索、代码审查和渗透测试可以借助工具。手工操作可以按步骤复现,只是重复执行更耗时,也更依赖判断与记录;自动化适合稳定、重复的断言,但不会自动发现所有未设计到的情形。

测试金字塔提供的是投入建议:用较多快速、易定位的单元测试守住规则,用适量集成测试守住协作,再用少量 E2E 守住关键旅程。若连一个简单字段边界都靠浏览器重走登录发文流程,通常会慢、脆弱、难定位;但层数和比例应适应项目,不能把“单元测试数量最多”当成质量证明,更不能靠它覆盖部署配置与所有用户体验问题。

4 预发布时 确认用户真的能把事情做完

系统测试看完整部署的行为,包括功能、兼容性与其他质量要求;E2E 则把关键路径走到底。应尽早建设,发布前在有代表性的环境中复核,而不是等到上线当天才开始写脚本。

对博客,完整旅程可以是:管理员登录 → 新建草稿 → 编辑并保存 → 发布 → 从公开页面读取 → 刷新后内容仍正确。最后的断言不能只有 URL 变化,还应确认标题、正文、发布状态与可见范围。

补三个相邻场景,常比再录一遍顺利流程有用:未登录或普通账号不能发布;保存失败时不会显示假成功;重复点击发布不会制造重复结果。还可以按实际使用情况检查手机布局、目标浏览器、返回/刷新、会话过期,以及取消编辑后的状态。

用 Playwright 时,优先按角色、标签等用户可见语义定位,等待可观察状态并使用可重试断言;每个用例使用独立账号或数据。若依赖第三方服务,使用获准的测试环境、沙箱或明确标注的替身,不要让回归测试误发真实邮件或触发真实交易。采用替身后,未验证的真实集成边界仍要记录。Playwright 测试实践

验收测试再回答另一件事:业务是否接受这个结果?例如“草稿仅作者可见、公开文章可被访客读取、失败时内容不会丢失”,应在开发前约定。即使页面完全按技术设计运行,也可能不满足使用者需求。业务确认、人工探索和自动化结果可以共同构成验收证据。

5 发布前模拟负载 观察性能与恢复能力

性能测试不只测“高并发有没有报错”,还可以比较正常负载、峰值、持续运行及负载解除后的表现。上线前针对关键路径建立基线,重大架构或流量变化后再复测。

先定义场景:访客读文章、管理员写入的比例,缓存冷暖、数据规模、并发或请求到达速率、持续时间,以及通过和停止条件。只说“同时有多少用户”还不够,因为用户操作频率不同,实际请求负载也不同。

常用观测包括吞吐量(req/s)、延迟分位数(p50/p95/p99)、错误率,以及负载解除后恢复到目标状态所需的时间。延迟不要只看平均值;还要关联 CPU、内存、连接池、数据库和下游请求,判断排队或资源耗尽发生在哪一段。

text
性能记录模板,不是实测结果
目标与授权:隔离测试环境、允许的操作与流量范围
可复现条件:版本、时间、机器配置、数据量、缓存状态
负载模型:场景比例、并发/到达速率、持续时间、停止条件
预先约定的门槛:延迟分位数、错误率、吞吐与恢复要求
执行后填写:真实观测、日志/链路证据、未覆盖条件

wrk、k6 等工具可以产生负载;k6 的 thresholds 能把指标门槛写成自动判定条件,但门槛应该来自业务要求和容量目标,不应照抄示例数值。压测只在明确授权的隔离环境中执行,约定资源预算、持续时间和停止条件,不能随手对生产站点或第三方服务施压。k6 阈值文档

看到延迟或错误上升,不能直接归因于 SSR,也不能立即下结论“加 CDN”“改 ISR”。先用日志、资源和链路证据定位;缓存能否使用,还取决于内容更新、权限和一致性要求。修复后在可比条件下复测,才有资格谈改善。

6 安全验证 同时看权限边界和部署暴露面

正常使用没报错,并不能说明恶意输入、越权访问或错误配置也安全。安全工作应从需求、开发和配置审查开始,上线前完成必要验证,上线后持续复测;不能把首次安全检查推到生产发布之后。

不同方法各自提供什么证据

方法关注点与常用工具不能省略的判断
SAST 静态应用安全测试不运行被测程序,分析源码等程序表示;如 SonarQube、Semgrep、安全相关 ESLint 规则可提示注入、不安全加密等风险,硬编码密钥也可用专门的秘密扫描;结果受规则和数据流分析能力限制
DAST 动态应用安全测试对运行中的应用进行外部探测;如 ZAP、Burp Suite 的扫描功能、nuclei 的相关模板可能发现 SQL 注入、XSS、认证或目录遍历问题;覆盖受登录状态、可达路径、规则和配置限制
SCA 软件成分分析识别依赖中的已知漏洞;如 npm audit、Snyk,配合 Dependabot 警报与更新要评估实际使用版本、依赖路径、可达性和部署位置,不能把告警数量直接当成可利用漏洞数量
渗透测试由测试者依据目标和反馈调整策略,可组合手工验证与自动化工具更适合验证业务逻辑、权限边界与漏洞组合;也受范围、时间和测试者能力限制
配置审计审查应用、服务器、Nginx、Docker、云服务和 CI/CD 配置源码正确不代表部署后的权限、网络与密钥管理正确

SAST 不等于全部白盒测试,DAST 也不等于全部黑盒测试。白盒、黑盒、灰盒描述设计依据或掌握的信息;安全测试描述目标。渗透测试可以采用不同的信息条件,并非只能“从外部攻破”,也不是工具扫描报告的另一个名字。OWASP 安全测试框架

在授权范围内,渗透测试通常从信息收集与目标确认开始,按约定进行端口/服务识别、漏洞探测和必要的利用验证;影响评估也必须留在范围内,不能把“后渗透”理解为任意扩大访问。结束后清理测试账号与数据,保留审计证据并报告,修复后复测。大版本、权限模型或部署方式改变时,应追加针对性验证,而非依赖去年的报告。

具体到发文系统,检查不应止于“访问后台会跳转登录页”:还要确认未授权请求的响应、缓存和流式输出没有带出草稿数据。认证检查放在读取敏感数据之后是需要审查的风险,但“查过数据库”本身不等于已经泄露,泄露结论需要实际输出证据。SQL/XSS/SSRF、CSRF、Host/HTTP 头注入等也需要针对性的安全用例,不能靠正常登录发文顺带证明安全。

依赖告警要处置 也要验证更新影响

npm audit 查询已知依赖漏洞;本文不附虚构的漏洞数或未经核实的包名。收到报告后,核对公告、受影响版本、依赖链、触发条件与修复版本。生产镜像没有某个包、相关路径不可达,可能降低运行时风险,但构建和 CI 使用的依赖仍有自己的风险;“只是 devDependency”不等于可以忽略。

npm audit fix 默认尝试安装兼容更新;--force 可能越过版本范围并带来破坏性变化。不要盲目更新或降级,也不要因“暂时不可达”就永远搁置:记录依据、负责人和复核条件,更新后运行相关回归测试。npm audit 文档

部署配置与公开信息一起核对

入口与传输。 检查 TLS 证书的有效期、域名和链,协议及密码套件采用当前安全配置;支持 TLS 1.2 时关注 ECDHE 等前向保密选择,TLS 1.3 则不能只看套件名字判断密钥交换。Nginx 要按业务验证 Host 处理、代理配置,以及 client_max_body_size 与应用层上传限制是否协调。OWASP TLS 指南

HSTS、CSP 和防嵌入策略要检查实际响应与兼容性,不是有个头就算完成。CSP 的 frame-ancestors 可用于防嵌入,X-Frame-Options 可按兼容需求保留;HSTS 要确认 HTTPS 覆盖范围,CSP 要避免误伤必要资源。server_tokens off 可以减少版本披露,但不能替代补丁、鉴权或隔离。OWASP HTTP 响应头指南

运行环境与权限。 检查镜像及其层中没有密钥或敏感文件,不开放无用端口;私有镜像仓库不应允许匿名拉取,公开镜像则按公开发布意图检查内容。数据库公网暴露、云服务 IAM、CI/CD 凭证与部署脚本都要按最小权限审查。密钥不硬编码,使用受控的秘密管理或运行时注入;环境变量只是传递方式,日志、构建产物和客户端打包仍可能把它泄露出去。

公开信息(OSINT)。 核对 GitHub/Gitee 仓库的公开范围是否符合意图,源码、CI/CD 配置和邮箱是否暴露了不该公开的信息;检查 Git 历史、搜索引擎收录的敏感页面,以及 DNS 记录透露的架构信息。公开源码和 DNS 记录不天然等于漏洞,关键是是否暴露敏感资产或形成可利用风险。仓库按需设为 private,但不能用改私有或删除当前文件代替泄露处置;已经泄露的密钥应先撤销或轮换,再处理历史及其他副本。GitHub 敏感数据处置指南

7 发布时 看证据和未解决风险

前面的工作可以归到一条短流程:

text
开发:规则测试、接口集成、代码与安全审查
  → 合并:自动化回归、lint、构建,失败则阻断
  → 预发布:系统/E2E/验收,按风险做性能与安全验证
  → 发布:检查实际部署、关键流程和观测指标,必要时回滚
  → 持续运维:监控、备份恢复、依赖与安全复测

上线决定不需要再复制一张几十项的通用勾选表。留下一份简短记录,能回答下面五件事更有用:

  1. 测的是哪一版? 版本、构建产物、环境、测试范围与报告能对应;单元、集成和关键 E2E 的必要检查有结果,审查中的阻断问题已处理。
  2. 风险是否可接受? 安全与依赖告警经过评估;确认的漏洞已修复并复测,尚未解决或未覆盖的事项有明确决定与负责人,不能写成“全部通过”。
  3. 部署会不会改变结论? 生产权限、配置、TLS、密钥、镜像和网络边界已核对;构建或必要检查失败时不会继续部署,发布的是被验证的产物。
  4. 出问题能否发现? 日志收集、异常请求和性能告警有接收人,发布后有人观察关键指标与用户流程。
  5. 出问题能否恢复? 备份存在且恢复路径经过验证;回滚条件、操作人和步骤明确,数据库迁移与旧版本兼容性也考虑在内。

上线后的确认以低风险的冒烟检查和监控为主。额外安全验证仍须明确目标、方式和范围,不能把已发布当成随意扫描或压测的授权。之后每次变更继续回归,按风险定期复查依赖、安全与备份恢复。

注意

测试不能承诺百分之百安全。它的实际价值,是让团队在发布前知道哪些风险已有证据覆盖,哪些仍未覆盖,以及故障出现时如何及时发现、止损和恢复。

最近更新

Agent Engineering · 文章

Prompt Engineering:我会怎样把任务交给模型

沿着做事的顺序理解 Prompt Engineering:先把任务说明白,遇到复杂问题再组织处理过程,最后按需要检查结果。用十种常见方法和具体示例,讨论它们分别解决什么问题、怎样组合,以及什么时候不需要增加复杂流程。

2026年11月5日·23 分钟阅读

Agent Engineering

从 Prompt 到 Harness:我对 Agent 工程的理解

刚开始使用大模型时,我最关心的是:怎么把话说清楚,让模型给出更好的回答? 后来,我开始做 Agent,发现问题逐渐变了。模型不只是回答问题,它还要读取文件、调用工具、处理结果,甚至跨越多轮对话和多次运行,持续完成一项任务。 这时候,光把提示词写好已经不够了。我还需要考虑:模型每一步能看到什么?工具出了问题怎么办?

2026年11月5日·14 分钟阅读

学习流程

为了一个中文 hover,我和 AI 绕了一大圈

最近,我在读一个 Python Agent 项目的源码。 鼠标放到 argparse、ArgumentParser 这些名字上,编辑器会弹出一大段英文说明。这个悬停提示通常叫 hover,本来是帮助理解代码的,但对我当时的学习阶段来说,它又增加了一层障碍:我得先理解英文,再理解 API,最后才能回到眼前这段代码。

2026年11月1日·16 分钟阅读

目录

  • 1 先把测试名称放回各自的维度
  • 2 开发时 先验证规则和模块之间的约定
  • 单元测试把边界说清楚
  • 集成测试验证真实连接处
  • 白盒与黑盒决定怎样补用例
  • 3 合并前 让变化不会悄悄破坏旧功能
  • 4 预发布时 确认用户真的能把事情做完
  • 5 发布前模拟负载 观察性能与恢复能力
  • 6 安全验证 同时看权限边界和部署暴露面
  • 不同方法各自提供什么证据
  • 依赖告警要处置 也要验证更新影响
  • 部署配置与公开信息一起核对
  • 7 发布时 看证据和未解决风险
← 较早发布提示词的作用?
较晚发布 →ORM学习:从 Python 对象到数据库事务