- 数据分析
- CLI
- 数据可视化
【免费下载链接】visidata
A terminal spreadsheet multitool for discovering and arranging data
导读
本篇文章以 VisiData 仓库中的 dev/checklists/manual-tests.md 为骨架,系统梳理 VisiData 在发布前需要人工验证的 31 项核心功能,覆盖 cmdlog 录制与回放、长命令名执行、系统剪贴板、绘图与图片加载、大数据集、URL 加载、分屏窗口、外部编辑器联动、覆盖保存、宏录制、聚合器、批量模式与光标滚动等主题。通过结合 visidata/cmdlog.py、visidata/splitwin.py、visidata/_input.py、visidata/save.py 等源码实现与 visidata/tests 目录下的自动化测试,读者将掌握每一项功能的手动验证方法、底层工作机制、已知边界问题(bug)以及哪些部分已被 CI 自动化覆盖、哪些仍依赖人工兜底。
1. 清单背景:为什么需要「人工测试清单」
VisiData 是一个以交互为核心的终端电子表格工具,绝大多数功能(命令、快捷键、宏、分屏、编辑器联动)依赖 curses 终端交互,天然难以被纯单元测试覆盖。仓库中的tests/目录与test-*.sh脚本自动化了大量加载、保存、命令回放路径,但仍有以下场景必须依赖人工验证:
- 真实网络与 TLS:本地 loopback 测试无法模拟真实 HTTPS 站点的 TLS 握手、重定向与动态 HTML。
- 真实终端按键序列:例如编辑单元格时按下
Ctrl+O唤起$EDITOR并取回结果的按键链路,只有真实终端才能完整复现。 - 多窗格分屏的栈结构行为:
Z/gZ/zZ/gTab涉及 sheet 栈的跨窗格搬移,自动化难以断言视觉与栈结构。 - 性能感知:批处理耗时、大数据集滚动流畅度等,需要人工"体感"验证。
因此 dev/checklists/manual-tests.md 以编号列表形式,成为每次发布前的最终人工验收关卡。
2. cmdlog 录制与回放(清单第 1 项)
2.1 录制机制
VisiData 的全局命令日志(cmdlog)由 visidata/cmdlog.py 实现。每条可回放命令在执行时被写入 cmdlog 表,其核心判定逻辑是isLoggableCommand()与isLoggableSheet():
isLoggableCommand返回命令是否应被记录,取决于命令是否带replay=False前缀或被列入非记录集合(visidata/cmdlog.py 中的nonLogged列表);isLoggableSheet排除 cmdlog 自身、OptionsSheet、ErrorSheet等内部工作表,避免"记录记录本身"的递归(visidata/cmdlog.py 第 85 行附近)。
除全局 cmdlog 外,每个 sheet 还有独立的cmdlog_sheet,因此open_vdj/save_vdj可以按 sheet 粒度保存/恢复操作轨迹。
2.2 人工验证点
清单要求逐项验证:
- 选项(options)的日志记录:执行
set-option类命令后,确认选项变更出现在 cmdlog 行中;选项记录依赖replayableOption与Settings.set(..., cmdlog=True)机制。 - 行与列的日志记录:对行、列的操作(如
add-row、add-column)应被完整记录。 - 空 sheet / 空行 / 空列的回放:当 cmdlog 中某条记录缺少 sheet、row 或 column 上下文时,回放应作用于当前sheet、row、column——这正是
moveToReplayContext(vd, r, vs)的职责(visidata/cmdlog.py):它读取回放行中记录的 sheet/row/col 位置,缺失部分则落回当前游标。 - 中止(abort):回放过程中按
Esc等键应中止后续命令,源码中replay_cancel(vd)与replayOne内if escaped:分支会提示replay aborted during <longname>(visidata/cmdlog.py)。 - 批量模式(batch mode):清单给出两条命令验证顺序无关性:
bin/vd -b -p tests/append.vd bin/vd -p tests/append.vd -b-b(batch)与-p(play cmdlog 文件)组合时,无论参数顺序如何,回放结果应当一致。回放执行的调度核心是vd._nextCommands.extend(cmdlog.rows)(visidata/cmdlog.py 中的replay(vd, cmdlog)),命令会被排队依次执行。
回放相关选项(visidata/cmdlog.py 第 7-8 行):
replay_wait:回放命令之间的等待秒数,默认0.0;replay_ignore_errors:是否在回放出错时继续而非中止,默认False(即出错即中止)。
2.3 自动化覆盖现状
cmdlog + replay的大部分路径已被自动化覆盖:tests/下存在大量.vd/.vdj回放脚本与对应 golden 输出(例如 tests/append.vd、tests/sortorder.vdj、tests/freq-summary.vd),配合dev/test-all.sh、tests/test-vdx.sh等脚本运行。人工测试主要补足"真实终端下的中断/恢复、空上下文回放"等交互细节。
3. 长命令名执行与系统剪贴板(清单第 4、5 项)
- longname-exec(第 4 项):VisiData 每个命令都有唯一的长命令名(longname),如
splitwin-half、save-sheet。人工验证长命令名能通过:命令行直接执行,且结果与快捷键触发一致。命令定义统一走addCommand(keystrokes, longname, execstr, helpstr, replay=True)接口(visidata/settings.py 中的addCommand),replay=True保证长命令名执行也会被 cmdlog 记录并可回放。 - syscopy(第 5 项):系统剪贴板复制。实现位于 visidata/clipboard.py,核心函数为
syscopyValue、syscopyCells、syscopyCells_async;tests/test_commands.py中syscopy被列入自动化命令测试(visidata/tests/test_commands.py)。人工验证重点:在无 X 剪贴板的纯终端(如 SSH 会话)下,复制行为是否优雅降级(依赖vd.copyToClipboard的兜底实现,见 visidata/deprecated.py 的copyToClipboard)。
4. 绘图与图片加载器(清单第 6 项)
清单要求验证plots 与图片加载器(如 png),并特别关注plot 与鼠标(mice)之间的关系。
- 绘图能力由 visidata/canvas.py 与 visidata/graph.py 提供:
Canvas负责像素绘制(plotpixel、plotline、plotlabel、plotlegend),GraphSheet在其上叠加坐标轴、参考线与缩放(zoomTo、resetBounds)。 - 鼠标交互:
plotterMouse()、plotterCursorBox()将终端鼠标坐标换算为画布坐标,canvasMouse()与go_mouse(visidata/mouse.py)配合实现拖拽、缩放、平移。人工验证时应重点测试:在图形上拖动鼠标是否平滑跟随游标、点击是否准确命中所选数据点、缩放框选是否与视觉一致。 - 图片加载:png 等位图通过
loaders下的加载器读入为像素行,与绘图共用 Canvas 渲染管线。可先用sample_data/vdlogo-160x24.png这类小图验证加载与逐像素显示。
5. 大数据集测试(清单第 10 项,311)
清单以311数据集为代表,验证大表格的加载、滚动与操作性能。仓库sample_data/与tests/中对应场景包括tests/issue350.vdj、tests/issue655.vdx、tests/issue733.vd等(多为 311 相关 issue 回归),以及tests/test-perf.sh性能脚本。
人工验证要点:
- 加载大文件时底部状态栏出现异步进度条(
Progress机制,visidata/threads.py); - 上下滚动、
PgDn翻页、列宽自适应在大数据集下不卡顿; - 对大数据集执行
freq、pivot、join等重操作时,界面保持响应、可随时中止(cancelThread/EscapeException)。
6. URL 加载(清单第 15、22 项)
清单区分了已自动化与仍需人工的 URL 场景:
- 已自动化:HTTP URL 加载与 open-row 跟随 HTML 链接,通过
tests/test-url.sh针对 loopback 服务器完成,相关用例见 tests/url 目录(page.html、usage.tsv)。 - 人工残余:
- 真实外网 HTTPS URL,例如
https://visidata.org/usage.tsv——覆盖 TLS + 真实网络的组合,CI 无法触达; - 真实外网 HTML 页面上的
open-row(例如 NASA 数据页或维基百科页)——验证open-row跟随链接的机制在真实 HTML 下的表现(机制本身已由tests/test-url.sh自动化)。
- 真实外网 HTTPS URL,例如
URL 路径的底层支持见 visidata/path.py:Path通过scheme()、is_url()、open_text()/open_bytes()抽象出网络文件句柄,加载器据此复用与本地文件一致的读取链路。网络缓存由 visidata/_urlcache.py 的urlcache()提供(默认缓存 1 天)。
7. 分屏窗口(清单第 16 项)——本清单最重的验证块
分屏由 visidata/splitwin.py 单独实现,含 5 个命令与 1 个选项:
| 快捷键 | longname | 行为 |
|---|---|---|
Z | splitwin-half | 确保分屏开启并把下层 sheet 推入另一窗格,默认 50% |
gZ | splitwin-close | 关闭分屏,重置所有 pane 与disp_splitwin_pct |
Tab | splitwin-swap | 跳到非活动窗格 |
gTab | splitwin-swap-pane | 交换窗格在屏幕上的上下位置 |
zZ | splitwin-input | 以输入提示设置分屏百分比 |
| 选项 | disp_splitwin_pct | 第二个 sheet 在屏幕上的高度百分比,默认 0(关闭) |
核心实现splitPane(sheet, pct)(visidata/splitwin.py 第 10-17 行):若当前活动栈还有第二层 sheet,则取undersheet.pane的另一侧 pane 编号,vd.push(undersheet, pane=pane)将其推入另一窗格并切换vd.activePane。窗格归属记录在sheet.pane属性(默认 1),vd.activePane = 1表示活动窗格编号从 1 起。
7.1 清单要求的三个子测试
- 测试 1(关闭后栈可访问):打开 2 个文件 →
Z→ 确认第一个窗口(pane 1)处于活动 →Tab切换 → 分别尝试关闭上/下窗格,确认关闭分屏后(splitwin_close把所有pane重置为 1),两个窗格中的所有 sheet 都能在结果栈中访问。 - 测试 2(ColumnsSheet 分屏栈行为):打开 2 个文件 →
Z→ 在一侧打开ColumnsSheet→ 再Z→ 检查 sheet 栈:columns sheet 应保持在原位,而其下层的源 sheet 应被移动到另一窗格的栈顶。清单还记录了一个已知 bug:在底部窗格按Shift+Z时,其第二个 sheet 会变成顶部栈的第二个 sheet,而非顶部栈的第一个 sheet——验证时需在两侧各复现一次,确认该 bug 的触发范围。 - 测试 3(单文件与单层栈边界):仅一个文件时按
Shift+Z;或两个窗格各自的栈都只有一个 sheet 时按Shift+Z,均不应产生异常或空窗格。
7.2 窗格操作专项
gZ(splitwin-close):两个窗格都要测试;关闭后移动光标,界面不应出现闪烁(flickering);再按Z重新分屏,两侧行为一致。zZ(splitwin-input):应只改变窗口尺寸,不改变其他任何状态;正负值都要测试。清单标注一个疑似 bug:负值会导致窗格归属互换(gTab的实现即disp_splitwin_pct = -disp_splitwin_pct,负值天然被用作"交换"语义,需人工确认这是特性还是缺陷)。gTab(splitwin-swap-pane):应交换两个窗格;两个窗格都要测试。另一个疑似 bug:第二个窗格尺寸较小时,交换后是否应围绕光标位置重新定向——这是待人工确认的交互细节。- 活动窗格内的光标:在两个窗格中分别移动光标,确认输入焦点与高亮始终跟随
vd.activePane。
8. 外部编辑器联动:edit-cell+Ctrl+O(清单第 18 项)
8.1 工作机制
单元格编辑时按Ctrl+O会启动$EDITOR编辑当前值并取回结果。按键处理在 visidata/_input.py 第 276-283 行:
elif ch == 'Ctrl+O': edit_v = vd.launchExternalEditor(v) if self.value == edit_v: raise EscapeException(ch) # 编辑器未改动,单元格保持不变 else: self.value = edit_v return True # 编辑器改动了内容,接受新值launchExternalEditor的完整链路(visidata/editor.py):
- 用
TempFile()创建临时文件,写入当前单元格值(第 47-50 行); launchExternalEditorPath调用launchEditor(path, '+<linenum>')——launchEditor读取$EDITOR环境变量(未设置则vd.fail('$EDITOR not set')),在SuspendCurses()上下文(先curses.endwin()退出窗口模式,结束后reset_prog_mode()恢复)中subprocess.call启动编辑器(第 26-32 行);- 编辑器退出后重新读取临时文件内容,
rstrip('\n')去掉编辑器必然追加的末尾换行,返回作为单元格新值(第 62-67 行)。
8.2 自动化覆盖与人工残余
清单明确指出:launch + readback 机制已在visidata/tests/test_editor.py自动化(该测试用假$EDITOR脚本验证launchExternalEditor('hello') == 'EDITED-hello'等场景,见 visidata/tests/test_editor.py);只有编辑器内部的Ctrl+O按键本身需要人工验证——即真实编辑器(vim/nano 等)会话内触发,确认保存退出后单元格确实取回编辑结果,且编辑器未改动时单元格保持不变。
9. 覆盖保存overwrite=c(清单第 19 项)
清单要求:以overwrite=c保存到已存在文件时,出现<file> exists. overwrite?提示,输入y/n应分别真正覆盖/中止。
9.1 底层实现
选项定义于 visidata/modify.py 第 10 行:overwrite默认值'c',取值语义为c=check(询问确认)、n=no/readonly(禁止覆盖),并通过optalias提供readonly/ro别名。核心逻辑:
couldOverwrite(vd):overwrite以c或y开头才可能允许覆盖(第 18-20 行);confirmOverwrite(vd, path, msg):路径不存在直接放行;否则按选项分支——n开头直接vd.fail('overwrite disabled');c开头弹出{path.given} exists. overwrite?确认框,vd.confirm在用户回答y时通过、n/Esc时抛出EscapeException中止(第 24-35 行)。
保存流程saveSheets(vd, givenpath, *vsheets, confirm_overwrite=True)(visidata/save.py 第 124-173 行)在确定 filetype 后调用vd.confirmOverwrite(givenpath);save-sheet-really命令则显式传confirm_overwrite=False实现"不询问直接存"。
9.2 自动化覆盖
清单注明:覆盖保存的其余路径——fallback(无对应 saver 时回退默认格式,见save.py第 164-170 行)、block(多 sheet 保存到非目录时vd.fail)、overwrite=y/n、多 sheet 保存——已由tests/test-save.sh与tests/test-filetype.sh自动化。人工只需验证真实终端下提示框的y/n交互。
10. 宏录制与聚合器(清单第 21、24 项)
- 宏录制(第 21 项):验证
startMacro→ 操作 →saveMacro的完整链路。实现见 visidata/macros.py:宏本质上是复用了 cmdlog 的录制行(afterExecSheet把命令写入宏 cmdlog),setMacro/runMacro/loadMacro负责绑定快捷键、执行与从.vd文件装载。人工验证:录制一段包含选择、排序、新增列的操作,保存为宏后在新会话中重放,结果应与录制时一致;tests/macros/test_macro.vd提供了可参考的宏文件样例。 - 多个聚合器通过 palette
+添加(第 24 项):验证在ColumnsSheet上按+(addcol-aggregate)弹出聚合器选择面板,可连续选择多个聚合器(如 sum、mean、min、max、count、stdev 等)一次添加到当前列。聚合器注册体系在 visidata/aggregators.py:aggregator()/aggregator_list()注册聚合函数,chooseAggregators()提供交互选择,addAggregators(sheet, cols, aggrnames)批量添加,memo_aggregate缓存分组结果。tests/aggregators-cols.vdj、tests/aggregators-set.vd、tests/aggregators-errors.vd等脚本验证了对应行为。
11. 批处理与z;管道命令(清单第 25、26、27 项)
- 第 25 项(性能基准):计时运行
time vd -p tests/quit-nosave.vdj并记录耗时,与 PR #2369 的基准对比,用于监控启动与退出的性能回归。性能测试脚本参见tests/test-perf.sh与dev/PERFORMANCE.md。 - 第 26 项(
z;管道):使用z;命令后输入一条命令,例如echo "| Ceci n'est pas une pipe",验证 shell 管道执行:z;触发exec_shell(visidata/shell.py 的inputShell与exec_shell),把命令输出转化为行(addShellColumns可为输出追加 shell 列);带引号的竖线|应作为字面字符传给 shell,验证转义处理。 - 第 27 项(batch + inline 双加载可编辑性):
vd -b -i -p tests/fill.vdj sample_data/a.tsv-i表示 inline(加载后停留在首行数据并立即接受编辑,而非进入帮助页),-b表示 batch(无交互)。清单要求确认:benchmark(tests/fill.vdj产生的填充表)与sample_data/a.tsv两个 sheet 都是可编辑的——即 inline 模式下即使批处理回放结束,工作表中的数据仍允许修改(hasBeenModified/修改追踪见 visidata/modify.py)。
12. 光标与滚动行为(清单第 28-31 项)
最后一组为纯交互验证,涉及cursorDown、页翻页与窗口滚动逻辑(visidata/movement.py、visidata/sheets.py 的topRowIndex/bottomRowIndex/cursorDown):
- 第 28 项:连续按
j滚动到底部,验证最后一行的显示与底部边界。 - 第 29 项:从第 1 行按
PgDn,应停在顶部并恰好向前翻一页——验证pageLeft/翻页语义与"恰好一页"的取整。 - 第 30 项:先
3xj移动 3 行,再PgDn,光标相对位置应保持——即翻页后光标仍停留在相对相同的行位,验证topRowIndex与游标行的联动计算。 - 第 31 项:
ZZ退出,验证退出时对未保存修改的确认提示(confirmQuit,visidata/sheets.py)与quit.vdx等退出脚本的兼容性。
13. 自动化与人工测试的分工总览
结合清单标注与仓库测试布局,可以得出如下分工:
| 功能 | 自动化覆盖 | 人工残余 |
|---|---|---|
| cmdlog + replay | tests/*.vd/.vdj+ golden 输出 | 空上下文回放、中止交互 |
| URL 加载 | tests/test-url.sh(loopback) | 真实 HTTPS/TLS、真实 HTML open-row |
| 编辑器联动 | visidata/tests/test_editor.py | 编辑器内Ctrl+O按键 |
| 覆盖保存 | tests/test-save.sh、tests/test-filetype.sh | <file> exists. overwrite?的 y/n 交互 |
| 分屏窗口 | 无专门自动化 | 全部 5 个命令 × 多窗格组合 |
| 光标/滚动 | 部分命令测试 | 翻页相对位置等体感验证 |
发布流程参考 dev/checklists/release.md,人工测试清单通常作为 release 流程的最终关卡,与 dev/checklists/feature.md(新功能自检)和 dev/checklists/add-command.md(新增命令自检)配合使用:新命令应自带自动化测试,而本清单聚焦于跨模块交互与真实环境行为。
14. 结语
dev/checklists/manual-tests.md虽然只是一份编号清单,却精确刻画了 VisiData 中最"人工密集"的功能面:cmdlog 回放的正确性、分屏窗口的栈结构、外部编辑器的双向通信、覆盖保存的交互语义。每一行都对应着 visidata 目录中可考的源码实现与tests/下的自动化边界。对照源码执行这份清单,既是发布前的验收,也是深入理解 VisiData 事件调度、sheet 栈与终端交互模型的绝佳路径。
- 数据分析
- CLI
- 数据可视化
【免费下载链接】visidata
A terminal spreadsheet multitool for discovering and arranging data
相关推荐
Windows Calculator 手动测试全指南:从 Smoke 测试到回归验证的发布前检查清单
Windows Calculator 手动测试全指南:从 Smoke 测试到回归验证的发布前检查清单 导读 ManualTests.md https://lin
桌面应用Thunderbird for Android 发布前手动测试清单:从 Smoke 快速回归到全量 Release 验证
Thunderbird for Android 发布前手动测试清单:从 Smoke 快速回归到全量 Release 验证 导读 本文完整解析 Thunderbi
移动开发企业应用ISO3166 PHP库常见问题解答:解决90%开发者遇到的集成难题
ISO3166 PHP库常见问题解答:解决90%开发者遇到的集成难题 ISO3166 PHP库是一个提供ISO 3166 1数据的PHP工具包,帮助开发者轻松处
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考