测试全绿,为什么界面还是难用?
一句话总结
类型检查、React DOM 行为检查和真实浏览器检查,回答的是不同的问题。在谈论检查结果时,要同时说明观察到了什么。
为什么需要它
鲸鱼搜索一直保持到了最后,所有状态检查都通过了。可是在手机上,搜索按钮跑到了屏幕之外,用键盘输入的过程中只要响应到来,焦点就会移到结果区域。实现者说测试是绿灯,用户却说仍然用不了。这并不是二者中有一方在说谎,而是它们看的是不同的对象。
本课程把检查的范围分开。学生的源代码在通过类型检查之后,会用真实的 React 在 DOM 环境中渲染,并读取请求前后的状态。DOM 环境实现了浏览器的部分 API,但并不是能够还原文字排版或真实绘制成本的布局引擎。如果仅凭这个结果就判定屏幕宽度或性能,就会变成毫无根据的自信。
工作原理
把要检查的行为拆分成小的事件。渲染组件,提交搜索,让指定的响应完成,在 React 的更新被反映之后读取 DOM。React 的异步 act 就是处理这个边界时使用的工具。随意睡眠 3 秒的做法,在快的电脑上只是浪费时间,在慢的环境中仍然可能先读到。
| 检查层 | 可以确认的例子 | 仅凭这一层无法知道的内容 |
|---|---|---|
| TypeScript | 各状态必需的数据与类型 | 响应实际到达的顺序 |
| React+DOM | 逆序响应之后的结果、effect 清理 | 像素布局与绘制成本 |
| 真实浏览器 | 键盘路径、窄屏幕、渲染记录 | 所有辅助技术的可用性 |
| 用户观察 | 是否理解说明并完成任务 | 其他所有用户的体验 |
在可访问性方面,输入的名称、真实的 form 提交、结果变化的提示以及焦点的保持,是相互关联的。告知有新结果,与强行把焦点移到结果上,是两回事。如果用户仍在不断修改搜索词,就必须在保留当前输入位置的同时传达变化。不要把通过自动检查表述为屏幕阅读器可用性的认证。
性能也要分时间来看。从发出请求到收到响应之间的等待,与用 React 计算结果并绘制到界面上的成本,是不同的。如果只有网络等待很长,即使加上 memo,响应也不会变快。如果结果已经到达,而一次性显示 1 万行的成本很大,那么靠网络重试也解决不了。
不要把 React Profiler 的渲染时间与浏览器的布局、绘制、网络记录当作同一个数字。测量前要记录数据量、开发或生产构建、设备、重复次数。比起一次漂亮的数字,同样条件下的多次观察更有用。这个阶段不要为了凑目标数字而编造观察值。
如何留下观察记录
好的记录,比只写结果数字的表格更先说明复现条件。请只把实际做过的事情填进下面的表格。尚未运行的项目,不要用看似合理的值填空,而要保持为“未确认”。
| 项目 | 要记录的内容 |
|---|---|
| 对象 | 源代码版本、修改过的函数、构建类型 |
| 环境 | 浏览器版本、屏幕宽度、设备条件 |
| 输入 | 数据数量、搜索词、提交与响应的顺序 |
| 预期 | 最后应该留下的结果与焦点位置 |
| 观察 | 实际结果、错误、渲染或网络记录 |
| 剩余范围 | 其他界面、辅助技术、与真实服务的连接 |
例如,只记录“鲸鱼之后送达了猫”是不够的。必须写明请求是按什么顺序发出的、是不是忽略取消的模式、是否在确认最新结果之后才送达过去的响应。如果缺少这些条件,同事拿到同样的代码也无法复现问题。
在性能改进前后,一次只改变一个条件,也更容易解读。如果同时改变显示的行数、网络延迟和构建类型,就很难知道是哪一项改变起了作用。如果减少了显示数量,就要把总结果数和当前显示数告知用户,避免让他们误以为丢失了资料。为了看起来快而悄悄丢弃结果,是与性能改进不同的产品变更。
在现场相遇的样子
向客户说明故障修复结果时,也适用同样的原则。与其说“测试通过”,不如说“逆序的成功与失败以及卸载时的取消已经复现并确认,而实际的移动端会话尚未确认”,这样下一个审查对象就清楚了。亮出没有确认的范围,会提高检查的可信度。
评分工具本身也是验证的对象。除了正确答案之外,还要放入无条件返回 success 的代码、中途 exit 的代码、永不结束的代码。如果只相信退出码 0 或 stdout 中的 PASS 字样,即使学生代码碰巧跳过了检查,也可能通过。还要确认评分结果是否收集到了最后,以及学生的原始代码是否没有被改动。
要亲自确认的内容
把 DOM 检查和真实浏览器观察分别记录。用表格整理哪项检查发现了哪种缺陷,并留下尚未观察的范围。长列表的实测要在真实浏览器中进行,不要提交从 DOM 模型中得到的时间来代替。
工具的范围请参考 React act、React Profiler 和 jsdom 说明。