鸿蒙 PC Markdown 编辑器原生测试:ohosTest 验证文档与大纲服务

📅 2026/7/26 5:04:58 👁️ 阅读次数 📝 编程学习
鸿蒙 PC Markdown 编辑器原生测试:ohosTest 验证文档与大纲服务

鸿蒙 PC Markdown 编辑器原生测试:ohosTest 验证文档与大纲服务

Web自动化可以证明 CodeMirror和预览逻辑,却无法证明 HarmonyOS Core File Kit在目标运行时的真实读写语义。BOM、fsync、AtomicFile、应用沙箱和 ArkTS字符串偏移必须在 ohosTest环境执行。否则 Node测试全绿,设备文件仍可能短写或格式变化。

本文基于 OhMarkdown,说明 Hypium测试模块、沙箱隔离、字节读取、故障注入、大纲偏移和设备结果。代码位于 https://gitcode.com/VON-/codex_md_oh,对应提交3a9146e

测试模块独立于 entry 主模块

entry/src/ohosTest/module.json5

{ "module": { "name": "entry_test", "type": "feature", "deviceTypes": [ "phone", "2in1" ], "deliveryWithInstall": true, "installationFree": false } }

测试目标同时声明 phone与2in1,当前重点在 MateBook Pro 2in1模拟器。入口文件只注册服务测试:

importdocumentServiceTestfrom'./DocumentService.test';exportdefaultfunctiontestsuite(){documentServiceTest();}

保持入口简单,测试分组由具体文件负责。新增 Workspace或 Recovery测试时可独立文件注册,不把所有逻辑堆在 List.test。

使用应用测试上下文

constcontext=abilityDelegatorRegistry.getAbilityDelegator().getAppContext();consttestPath=`${context.filesDir}/${TEST_FILE_NAME}`;

测试文件位于测试应用沙箱,不污染用户 Documents,也不依赖系统选择器。使用真实context.filesDir让 RecoveryService路径与生产一致。

沙箱测试不能替代用户 provider URI,但适合可重复字节和故障场景。选择器授权仍在模拟器手工/自动化层验证。

beforeEach 和 afterEach 双重清理

beforeEach(async()=>{if(awaitfileIo.access(testPath)){awaitfileIo.unlink(testPath);}if(awaitfileIo.access(faultPath)){awaitfileIo.unlink(faultPath);}if(awaitfileIo.access(faultDirectory)){awaitfileIo.rmdir(faultDirectory);}awaitclearPendingSaveBackup(context.filesDir);});

afterEach重复相同清理。before保证上次异常中断不影响当前用例,after保证成功测试不影响下一项。异步文件操作全部 await,不能让清理与测试并发。

删除顺序先文件后目录,避免非空目录 rmdir失败。恢复备份是共享沙箱资源,也必须清理。

测试辅助写入不复用被测函数

asyncfunctionwriteRawText(path:string,content:string):Promise<void>{constfile=awaitfileIo.open(path,fileIo.OpenMode.CREATE|fileIo.OpenMode.READ_WRITE);try{constwrittenBytes=awaitfileIo.write(file.fd,content,{offset:0,encoding:'utf-8'});awaitfileIo.truncate(file.fd,writtenBytes);awaitfileIo.fsync(file.fd);}finally{awaitfileIo.close(file);}}

构造输入不调用writeUtf8Document,否则用被测序列化器生成期望文件,会让同一缺陷同时存在于准备和验证。辅助函数只按给定字符串原样写 UTF-8。

更严格可断言 writtenBytes等于预期,测试辅助自身也要可靠。当前小语料在设备验证中稳定。

字节比较绕过解码

conststat=awaitfileIo.stat(file.fd);constdata=newArrayBuffer(stat.size);constbytesRead=awaitfileIo.read(file.fd,data,{length:stat.size});constbytes=newUint8Array(data,0,bytesRead);letresult='';for(letindex=0;index<bytes.length;index+=1){result+=bytes[index].toString(16).padStart(2,'0');}

返回十六进制用于assertEqual。BOM与 CRLF不能通过再次调用 readUtf8Document验证,因为读取器会抽象它们;必须比较原始字节。

生产测试若扩展到大文件,应用哈希更节省内存。当前数十字节 fixture用完整 hex能在失败时直接看到差异。

BOM 与 CRLF 用例

it('UTF-8 BOM 与 CRLF 保存后字节一致',0,async()=>{constoriginal='\uFEFF# 鸿蒙 PC\r\n\r\n'+'第一行\r\n第二行\r\n';awaitwriteRawText(testPath,original);constbeforeHex=awaitreadBytesAsHex(testPath);constopened=awaitreadUtf8Document(testPath);expect(opened.format.hasUtf8Bom).assertTrue();expect(opened.format.lineEnding).assertEqual(LineEnding.CRLF);awaitwriteUtf8Document(testPath,opened.content,opened.format);expect(awaitreadBytesAsHex(testPath)).assertEqual(beforeHex);});

它同时验证读取格式元数据、内存正文去 BOM、保存序列化和 Core File Kit写入。字节相等是最终门槛。

用例名使用中文,设备报告直接表达目标。第二个参数0是测试过滤/级别参数,异步函数由 Hypium等待。

Mixed 换行归一

输入包含 CRLF、LF和单独 CR,读取应为 MIXED。指定 LF保存后重新读取,正文必须全是\n,检测为 LF。

该用例验证的是服务显式转换,不涉及 UI策略对话框。UI取消、LF、CRLF三按钮需要模拟器交互测试。测试层必须说明覆盖范围,不能把服务用例冒充完整工作流。

目录删除制造确定故障

awaitfileIo.mkdir(faultDirectory);awaitwriteRawText(faultPath,previousContent);awaitsavePendingSaveBackup(context.filesDir,{version:1,documentUri:faultPath,documentName:TEST_FILE_NAME,previousContent,hasUtf8Bom:false,lineEnding:LineEnding.LF,updatedAt:Date.now()});awaitfileIo.unlink(faultPath);awaitfileIo.rmdir(faultDirectory);

目标父目录不存在,writeUtf8Document必然失败。相比模拟磁盘满,目录删除易重复且不影响设备全局。异常后断言 backup仍能加载、previousContent正确,再重建目录并用备份恢复。

这项用例证明失败不会清理唯一旧版本。它尚未覆盖写到一半失败和 fsync失败,需要可注入文件适配层或平台故障工具。

大纲服务在 ArkTS 运行时验证

describe('Markdown 大纲',()=>{it('设备端提取标题与 UTF-16 跳转偏移',0,()=>{constcontent='# 鸿蒙 PC\n\n正文\n---\n\n'+'```md\n## 代码标题\n```\n\n'+'### 目标标题';constheadings=extractMarkdownHeadings(content);expect(headings.length).assertEqual(3);expect(headings[2].offset).assertEqual(content.indexOf('### 目标标题'));});});

无需文件 I/O的纯函数也值得在 ArkTS测试,确认目标运行时正则和字符串索引。中文让 UTF-8字节方案无法误通过,代码围栏验证状态机过滤。

UnitTestBuild 与设备执行不同

HvigorUnitTestBuild验证测试代码能够编译打包,不等于用例已在设备运行。质量记录分别写:UnitTestBuild成功;ohosTest安装并在 MateBook Pro 2in1执行4/4成功。

如果没有连接目标,只能宣称构建成功。测试报告中把“设备执行”与“调用链审查”分开,防止质量数字虚高。

鸿蒙 PC 测试后的应用

下图为设备测试使用的文档格式版本运行在模拟器中。ohosTest本身输出在测试运行器,应用截图证明同一服务进入真实 HAP。

理想证据还应保存测试运行器结果截图或结构化报告,但每篇文章至少包含应用内部画面。截图不替代4/4日志。

测试结果读取

设备执行结束应记录目标名、应用版本、构建模式、用例数、失败堆栈和时间。HDC连接断开、安装失败与断言失败是不同状态,脚本不能把“没有结果”当成功。

自动提取可解析 Hypium报告并生成 Markdown测试报告。日志中不得写 fixture之外的用户正文和 URI。

可扩展的测试结构

后续应拆分DocumentFormat.testRecovery.testOutline.testWorkspace.test,List只注册。共享临时目录助手可减少清理重复,但不能隐藏故障步骤。

参数化矩阵适合 BOM×换行×末尾换行;故障用例保持独立名称。每项先构造、执行、按字节/状态断言、清理。

当前边界

现有设备用例只有4项;AtomicFile强杀、用户 picker URI、两千项目录、权限撤销、主题生命周期和多标签关闭尚未自动化。模拟器通过不等于真机 provider行为。

结语

ohosTest把文本保真从算法推断带到 HarmonyOS真实运行时:Core File Kit写入、字节读取、沙箱备份、故障恢复和 UTF-16偏移都有设备断言。测试辅助不复用被测序列化器,前后清理保证隔离。

鸿蒙 PC编辑器的质量不能只有浏览器测试。凡是文件和系统 API参与的承诺,都需要在目标平台产生可重复证据,并诚实区分编译通过与设备执行通过。