简介:微信小程序测试报告(Word文档)为小程序开发、测试及项目管理人员提供了一套可直接使用或参考的测试文档范例。报告以某商城微信小程序为对象,系统梳理了功能、性能、安全、兼容性、UI与用户体验等测试维度的完整流程。资源仅1个Word文档,大小23KB,内容涵盖测试目的与范围、测试计划执行情况、测试用例执行结果,以及安全测试中的软件权限、数据安全、通讯安全等关键要点。报告中还记录了真实测试环境配置(不同型号安卓手机、微信版本、MySQL数据库)和典型问题,如MySQL版本过低导致前端数据未渲染、数据库最初设计不符合三大范式等,这些内容可作为实际测试排错的参考。目前已有3971人学习该文档,适合需要编写测试报告、规划小程序测试方案或了解测试过程细节的读者,可直接修改项目信息后套用,有效节省文档撰写时间。
1. “可直接使用”是个门槛:先想清楚给谁看
大多数测试报告写到最后变成“用例执行记录表”,领导翻三页找不到结论,开发翻十页找不到复现步骤,测试自己隔两周再看也忘了当时为什么判定失败。微信小程序测试报告难就难在它跨端、跨工具链,页面状态、网络、基础库版本、性能数据揉在一起,不整理直接贴出去,别人看不懂,自己也讲不清。“可直接使用”四个字看起来是交付要求,本质上是讲:报告不是给测试自己存档的,而是给产品、研发、运维和下一轮迭代看的决策资产。它要能回答三个问题——质量过不过关、哪里有问题、优先级怎么排。这篇顺着微信小程序测试报告从数据采集、指标计算到报告生成和防坑验证讲一条能落地的路,适合手里已经跑过测试但报告拿不出手的人,也适合刚要把小程序测试规范化的团队。
2. 数据从哪来:先解决采集,再谈报告结构
2.1 开发者工具自动化:用 miniprogram-automator 采集行为数据
报告的基础是执行数据。微信小程序测试最常见的执行载体是微信开发者工具自带的自动化能力,miniprogram-automator 这个库可以连接工具中打开的项目,代替手工点击和输入。比起纯手工记录,自动化跑一遍至少能拿到一致的路径、截图和调用链,报告里的“执行时间”“步骤结果”才站得住。
const automator = require('miniprogram-automator') async function run() { // 1. 连接开发者工具中已打开的项目 const miniProgram = await automator.launch({ projectPath: '/path/to/wechat-mini-program', // 指定基础库版本,避免默认版本和线上不一致 baseLibVersion: 'latest' }) // 2. 跳转到目标页面 const page = await miniProgram.reLaunch('/pages/index/index') await page.waitFor(500) // 3. 找到按钮并点击,模拟真实操作路径 const btn = await page.$('.order-btn') await btn.tap() // 4. 采集此时的页面数据和截图 const data = await page.data() await page.screenshot({ path: '/tmp/report/screenshots/order-submit.png' }) // 5. 断开连接 await miniProgram.close() } run().catch(console.error)这段逻辑不复杂,关键在三个参数。projectPath必须指向开发者工具导入过的项目根目录,不是代码仓库根目录;baseLibVersion建议固定到一个发布过的版本,不要每轮测试都跟着工具默认值漂移;page.waitFor(500)是给异步渲染留缓冲,数值根据页面复杂度调,粗暴统一设 3 秒反而掩盖渲染性能问题。截图的路径要按用例编号组织,报告里引用截图时直接拼相对路径,避免后面复制文件时挂链。
2.2 真机与云测:网络请求和日志的统一收集路径
自动化工具覆盖的是可控环境,真机上很多问题只有真实网络和真实机型才暴露。真机调试面板里能看到 Network 信息,但它没法直接导出结构化数据,我一般会在测试阶段给小程序挂一个调试开关,把 wx.request 的返回、耗时、状态码统一收集起来。
// 在 app.js 中挂一个全局请求拦截,测试模式下记录日志 const originalRequest = wx.request wx.request = function (options) { const startTime = Date.now() const report = { url: options.url, method: options.method || 'GET', startTime: new Date().toISOString() } const completeHandler = (res) => { report.cost = Date.now() - startTime report.statusCode = res.statusCode // 只在测试模式用,上线前要摘掉 if (wx.getStorageSync('test_mode')) { getApp().globalData.requestLogs.push(report) } } return originalRequest({ ...options, success: (res) => { completeHandler(res) options.success && options.success(res) }, fail: (err) => { completeHandler({ statusCode: -1 }) options.fail && options.fail(err) } }) }这样真机跑完一轮手工测试后,把globalData.requestLogs导出,就能看出哪些接口在弱网下超时、哪个域名在特定机型上解析失败。报告里不需要贴整个请求日志,但要在问题清单里附上请求耗时和状态码,开发定位时不用重新抓包。注意这个拦截只在测试模式开启,上线前必须确认开关关闭,否则全局改写 wx.request 会影响业务逻辑。
2.3 用云函数日志和微信后台数据做二次校验
很多团队的小程序后端是微信云开发,测试报告里涉及服务端数据时,直接从云函数日志拉取执行记录比让开发临时查库快得多。云开发控制台的日志里能看到每次云函数调用的时间、请求参数、返回结果和报错堆栈,测试执行时把时间窗口对齐,就能把前端截图和堆栈拼起来。
这里说一个常见误区:报告里写“接口报错”时,不要只贴前端红屏截图。前端看到 500,根因可能是云函数超时、数据库权限问题、参数格式不对,也可能是基础库对 Promise 风格调用的兼容问题。写进报告前至少去云开发控制台看一眼调用日志,确认错误发生在哪个环节,再决定把问题指派给前端还是后端。这个过程很多人跳过,导致测试报告被开发打回“无法复现”,本质上不是没法复现,是证据链只截了一半。
3. 从日志到指标:把测试数据变成能支撑结论的数字
3.1 三类指标:功能通过率、性能基线、缺陷逃逸
采集回来的原始数据堆在 JSON 里不会自己说话。测试报告里能直接支撑“可上线”结论的指标,我一般分成三类:功能执行指标、性能指标、缺陷管理指标。先看一张常用指标对照表,后面逐项说明计算口径。
| 指标类别 | 指标名 | 计算方式 | 建议阈值 |
|---|---|---|---|
| 功能执行 | 用例通过率 | 通过用例数 / 总用例数 | 核心流程 ≥ 98%,全量 ≥ 95% |
| 功能执行 | 核心用例通过率 | 冒烟用例通过数 / 冒烟总数 | 100%,有失败即阻断 |
| 性能 | 首屏渲染耗时 | 页面 onReady 时间 - 页面 onLoad 时间 | 中低端机 ≤ 3s |
| 性能 | setData 耗时占比 | setData 总耗时 / 页面交互总耗时 | 单次 ≤ 500ms |
| 性能 | 内存占用增量 | 操作前后内存差值 | 连续操作 5 次后 ≤ 50MB |
| 缺陷 | 缺陷逃逸率 | 线上 Bug 数 / (测试期 Bug 数 + 线上 Bug 数) | ≤ 5% |
功能通过率是最直观的数字,但要注意分母怎么定义。全量用例里包含大量重复的边界组合,把它们都算进去会把通过率稀释到没有参考意义。我一般是先算出“本轮新增和回归的核心用例通过率”,再算全量,报告里两个数都写,但结论以核心用例为准。
性能指标里,首屏渲染耗时在小程序里有个隐蔽问题:onReady触发并不代表用户看到了有效内容。如果页面上是异步请求回来才渲染列表,onReady可能已经跑了但页面还是白屏。计算首屏时间时,要么把setData和数据渲染完成作为采集点,要么在页面里埋一个显式的“内容已渲染”标记,不要直接用生命周期钩子之间的差值糊弄。
缺陷逃逸率这个指标需要线上数据配合,新项目第一轮测试拿不到,这时候报告里写“暂无线上基线”比硬编一个数字更诚实。数据积累几轮后,这个指标能反向校准测试用例的质量——如果线上 bug 总是集中在某个模块,说明测试设计时对这个模块的覆盖维度不够,下一轮要加用例而不是加执行轮次。
3.2 用例结果清洗:把无意义失败剔除出报告
自动化工具跑完一轮,原始结果里总有几条失败是不该进入报告统计的。常见的有三类:小程序的wx.getSystemInfoSync在新基础库上的 deprecated 警告导致回调时序变化、网络请求偶发超时但重试就能通过、page.waitFor给的缓冲时间不够导致下一画面还没渲染就截图。
// 简单的结果清洗逻辑示意 const rawResults = [ { id: 'TC001', status: 'fail', reason: 'request timeout after 10s' }, { id: 'TC002', status: 'fail', reason: 'element .order-btn not found' }, { id: 'TC003', status: 'fail', reason: 'setData error: Converting circular structure to JSON' } ] function cleanResults(results) { return results.filter((item) => { // 网络超时且同一用例上一轮通过,标记为 flaky,不算失败 if (item.reason.includes('timeout')) { return false } // 元素未找到要分情况:页面结构改动还是渲染未完成 if (item.reason.includes('not found') && item.retryCount >= 2) { return false } return true }) }这段代码的处理思路比代码本身更重要。timeout直接剔除是合理的,因为真机和模拟器网络环境差异太大,但报告里要单独列一个“不稳定用例”列表,连续三轮都超时的用例要反馈给开发查接口性能,而不是一直藏在过滤条件里。element not found剔除的条件是“重试两次仍找不到”,如果重试后能找到,大概率是等待时间不够,不是功能缺失。setData的循环引用问题不能剔除,这是代码缺陷,必须进缺陷清单。
3.3 截图和录屏文件如何对应到具体用例
测试报告的“可直接使用”很大程度体现在附件组织上。我见过最混乱的报告是把截图全部放在一个文件夹里命名为1.png、2.png,正文引用得靠猜。建议截图在采集阶段就按“用例编号-页面名称-操作步骤”命名,比如TC001-order-submit-before-click.png,然后在报告正文每个步骤后用 Markdown 图片相对路径引用。文件组织方式可以配合 2.1 中的 automation 脚本,在执行完每个关键操作后自动截图并重命名。
录屏文件体积大,报告正文里不要直接嵌视频,用表格列出来:用例编号、录屏文件路径、视频时长、对应缺陷编号。评审时有人想看再去找录屏,不会干扰阅读主流程。
4. 报告模板:让结论先于数据出现
4.1 第一页就该写清楚的三个结论
报告最前面应该是结论区,只写三件事:本轮测试结论(通过/有条件通过/未通过)、主要风险点、建议上线与否。测试主管或者产品经理看报告通常只给 30 秒,能不能在这段时间里抓住重点决定报告被认真对待还是被丢到一边。
结论区我一般这样组织:
测试结论:有条件通过 - 核心流程通过率 100%,全量通过率 96.2% - 风险点:支付回调在弱网环境下偶发 5s 延迟,需确认服务端重试机制已生效 - 建议:功能层面可上线,性能调优项排入下个迭代注意结论和数据的顺序,结论在前、数据在后,不要在结论区堆名词解释。写风险点时不要只写“存在支付超时风险”,要带上复现频率和影响面,比如“偶发(5 次中 1 次)”“影响用户下单支付”。
4.2 用例明细表的结构和字段
用例明细表是报告主体,也是开发看得最多的部分。每一行代表一个用例,但字段不要贪多,常见做法是控制在十个字段以内,字段多会导致维护成本高、漏填率高。
| 用例编号 | 模块 | 用例名称 | 前置条件 | 操作步骤 | 预期结果 | 实际结果 | 优先级 | 状态 | 缺陷编号 |
|---|---|---|---|---|---|---|---|---|---|
| TC001 | 购物车 | 商品加入购物车 | 已登录 | 点击商品详情页“加入购物车” | 购物车数量 +1 | 符合预期 | P0 | 通过 | — |
| TC002 | 购物车 | 删除购物车商品 | 购物车有商品 | 左滑商品,点击删除 | 商品从列表消失 | 崩溃退出 | P0 | 失败 | BUG-1024 |
操作步骤应该写成别人能照着走一遍的动作序列,不要写“验证购物车功能正常”这种无法执行的话。预期结果要可判断,比如“购物车角标数字从 0 变 1”比“购物车更新正确”更有用。
缺陷编号单独一列,和缺陷清单里的编号一一对应,便于从用例追到缺陷、从缺陷追回用例。
4.3 用 Node 脚本把 JSON 结果直接渲染成 Markdown 报告
手工整理几十条用例的表格是重复劳动,还容易出错。自动化跑完一轮后,结果通常是一份 JSON 或 CSV,这时候用脚本生成 Markdown 报告,保证数据一致性和排版统一。
const results = require('./test-results.json') const fs = require('fs') function generateReport(results) { const passCount = results.filter((r) => r.status === 'passed').length const totalCount = results.length const rate = ((passCount / totalCount) * 100).toFixed(2) const rows = results.map((r) => { return `| ${r.id} | ${r.module} | ${r.name} | ${r.precondition || '-'} | ${r.steps.replaceAll(';', '<br>')} | ${r.expected} | ${r.actual} | ${r.priority} | ${r.status === 'passed' ? '通过' : '失败'} | ${r.bugId || '-'} |` }).join('\n') const markdown = `# 小程序测试报告\n\n## 结论\n- 通过率:${rate}%\n\n## 用例明细\n\n| 用例编号 | 模块 | 用例名称 | 前置条件 | 操作步骤 | 预期结果 | 实际结果 | 优先级 | 状态 | 缺陷编号 |\n|---|---|---|---|---|---|---|---|---|---|\n${rows}\n` fs.writeFileSync('./report.md', markdown) return rate } const rate = generateReport(results) console.log(`通过率: ${rate}%`)这个脚本的逻辑是把测试执行产生的 JSON 数据按表格模板展开,字段从结果文件中读取,不需要人工复制粘贴。replaceAll(';', '<br>')是为了让操作步骤在 Markdown 表格里换行显示,JSON 里的步骤之间用分号隔开。bugId字段留空时显示为-,后续在缺陷清单里单独维护,避免报告和缺陷系统数据源冲突。脚本再往后扩展就是支持导出 HTML,但 Markdown 版本在微信工作群里沟通已经够用。
5. 高频失败原因与验证技巧:写进报告前先排除误报
5.1 基础库版本截断:白屏和组件样式差异先在结论区标注
小程序的基础库版本不同,页面的渲染表现和 API 支持程度会有差异。测试报告里最常见的“白屏”误报就来自这里:测试机基础库版本高,自动化模拟器基础库版本低,或者反过来,某些接口在低版本基础库返回的结果字段不同。
写进报告前,先在报告的“测试环境”小节里明确列出基础库版本。同一轮测试里,自动化环境和真机环境的基础库版本必须一致,不一致时生成的结果没有对比意义。遇到白屏时,先砍掉网络因素,再用两个不同基础库版本分别跑一遍,如果只有低版本白屏,问题定性为“基础库兼容性缺陷”,而不是“页面崩溃”,严重级别会降一档,处理优先级也不同。
5.2 setData 的路径坑:错误用法的误报率最高
小程序里setData的报错和性能问题在测试报告里出现的频率非常高。常见误用是用字符串路径更新深层嵌套对象,比如this.setData({'userInfo.nickname': that.data.nickname}),这种写法在数据层较浅时没毛病,一旦userInfo还没初始化,就会报Cannot read property 'nickname' of undefined。自动化工具跑到这一步就标红了,但业务代码的写法本身也确实是隐患。
写进报告时,要区分两种情况:一种是数据未定义导致异常,属于代码缺陷;另一种是 setData 传入的数据量过大导致渲染卡顿,页面无响应。前者按缺陷流程走,后者需要在报告里附上setData的数据体量和耗时数据,性能问题没有截图佐证就很难说服研发去查。
5.3 组件方法不存在和滚动失效:先重试再定性
自动化脚本报component "pages/index/index" does not have a method "navigatorClick",这种错误看起来像是页面方法丢了,实际经常是小程序组件化框架的事件绑定和页面栈切换导致的时序问题——方法还在,只是页面实例的引用没拿到。类似的还有苹果手机在 scroll-view 里滚动不动,或者是scroll-view内容高度设置没生效,本质是渲染机制差异。
处理方式是给这类失败用例加自动重试机制,同一用例连跑三次,三次都是同一失败原因才定级为失败。报告里对这类用例列出“重试次数”和“失败原因一致性”两个字段,让看报告的人能判断这个失败是间歇性问题还是必然缺陷。目前微信小程序的 iOS 端渲染机制和 Android 端有差异,很多流程在 Android 能跑通、iOS 就挂,重试确认还是失败的就标注“仅 iOS 复现”。
5.4 一个验证技巧:把失败用例压缩成最小可复现脚本
报告里被标为失败的用例,提交给研发之前先在本地做一次快速复核。具体做法是把业务路径中的前置动作全省略,只保留触发缺陷的最短操作序列,单独跑一个最小脚本。比如一个下单支付失败的问题,不要保留整个“注册、加购、填地址、提交订单、拉起支付”五步流程,直接写一个拉起支付参数固定死的页面,看支付回调状态。
这个方法能在一小时内帮测试人员过滤掉近半的“无法复现”。很多情况下,失败背后是测试数据的脏数据问题或操作顺序问题,而不是代码缺陷。经过最小脚本验证仍然失败的问题,再进缺陷清单,最终报告上的每个失败项都经过二次确认。这样的报告递出去,研发不用在本地反复构造数据,测试的结论也经得起推敲。
本文还有配套的精品资源,点击获取