Mac Sai 测试策略揭秘:862 个测试与「Sandboxed Logic」设计模式,让安全关键代码可 100% 测试
【免费下载链接】MacSaiMac Sai: the open-source Mac cleaner, optimizer, and malware scanner. A free, Apple-notarized alternative to CleanMyMac, built with Swift 6 and SwiftUI.项目地址https://gitcode.com/gh_mirrors/mac/MacSai点击查看免费下载Mac Sai是一款免费、开源的 Mac 清理、优化与恶意软件扫描工具是 CleanMyMac 的开源替代品使用 Swift 6 和 SwiftUI 构建。但真正让它在同类工具中「敢删文件」的不是某个功能而是一套工程上的硬承诺XCTest 测试套件共 862 个测试并把SafetyGuard和CleaningEngine这两个「生死攸关」的文件视为必须做到 100% 覆盖。这篇文章带你看懂 Mac Sai 是如何把「删除用户文件」这种高危操作从「我们相信它安全」变成「我们可以证明它安全」的。为什么清理软件的测试是「安全叙事」而非面子工程对于一款会删除用户文件的 Mac 工具来说测试覆盖率不是虚荣指标而是一条安全叙事。在加强测试之前Mac Sai 的安全承诺只建立在两样东西上一份保护路径黑名单定义清晰、容易验证一个我们相信能正确校验路径的SafetyGuard以及一个我们相信能遵守 dry-run 模式的CleaningEngine——但两者都几乎没被测试过。测试计划执行之后这些承诺变成了SafetyGuard达到 100% 覆盖并针对符号链接、路径穿越、NULL 字节、SIP 路径、受保护应用等对抗性用例CleaningEngine达到 100% 覆盖验证 dry-run 永不删除、trash 模式正确移动、permanent 模式名实相符、错误被优雅处理、且每步都有日志。这就是「声称安全」与「能够证明安全」之间的差距。完整的工程规划写在 docs/TESTING.md。「Sandboxed Logic」让逻辑与系统解耦的设计模式Mac Sai 低覆盖率的根源不是「测试写得少」而是业务逻辑和系统依赖纠缠在一起FileManager、NSWorkspace、Process、Mach API 以及真实文件系统散落在每个模块里。这导致纯单元测试几乎不可能除非你真的把 macOS 跑起来。解法就是「Sandboxed Logic」模式整个项目的架构因此分成两层MacClean薄外壳层负责把真实的系统实现接线起来承载 SwiftUI 视图和视图模型。MacCleanKit纯粹、可测试的库所有业务逻辑都以纯函数形式存在系统交互通过闭包注入不含FileManager/NSWorkspace/Process100% 可以从 XCTest 中测试。项目为此定了一条硬性架构规则由代码评审强制执行任何新增的业务逻辑要么必须是MacCleanKit里的一个纯函数要么是MacClean里一个调用纯 Kit 函数并注入系统闭包的薄封装。这个模式的落地效果可以用一个「前后对比」来理解——把一个分类过滤器从「内部直接调用FileManager」改写成「接收fileExists闭包」逻辑本身不变但从此可以在不碰真实磁盘的情况下被测试。纯逻辑层Sources/MacCleanKit/薄外壳层Sources/MacClean/Modules/包结构定义Package.swift862 个测试测试金字塔长什么样在 Package.swift 中测试被组织成两个测试目标MacCleanKitTests—— 针对纯逻辑库的单元测试占比最高、速度最快MacCleanTests—— 针对「外壳 真实文件系统」的集成与端到端测试。整体遵循一个经典的测试金字塔层级占比位置速度目的单元测试纯逻辑80%Tests/MacCleanKitTests/每例 10 ms抓住逻辑 bug集成测试真实 tmp 文件系统15%Tests/MacCleanTests/每例 1 s抓住接线 bug端到端完整「扫描→清理」周期5%Tests/MacCleanTests/每例 30 s抓住交互 bugUI 测试被刻意排除SwiftUI 视图在开发期靠肉眼 SwiftUI 框架本身来保证。其中「生死攸关」的两个文件被单独立项追求 100% 覆盖Sources/MacCleanKit/SafetyGuard.swift —— 目标100%因为它决定哪些文件能被删Sources/MacClean/Core/Cleaner/CleaningEngine.swift —— 目标100%它是真正的删除引擎。对抗性测试SafetyGuard 到底要防住什么打开 Tests/MacCleanKitTests/SafetyGuardTests.swift你会看到「必须拒绝」和「必须放行」两条清晰的用例线。它不是简单地测「列表里有没有某个路径」而是测门控逻辑本身必须拒绝受保护 / SIP/System/Library、/System、/usr/bin/ls、/bin/sh、/sbin/mount等系统路径/Applications/Safari.app等 Apple 系统应用指向/System的符号链接——解析之后拒绝防 TOCTOU符号链接链a→b→/System带..的路径穿越/tmp/x/../etc/passwd——解析之后拒绝含 NULL 字节的路径——出于安全考虑直接拒绝空路径、以及 Unicode 陷阱路径RTL 覆写、零宽字符——要被妥善处理而不是崩溃。必须放行~/Library/Caches/com.test.app这类用户缓存路径。此外还覆盖10000 个文件一批放行、10001 个文件整批拒绝、混合批次中「只拒危险项、放行其余」、以及validatePath的幂等性调用两次结果一致。这些用例正是把「我们相信SafetyGuard安全」变成「我们证明它安全」的关键。删除引擎测试dry-run / trash / permanent 三态各归其位CleaningEngine的测试围绕三种删除模式展开见 Tests/MacCleanTests/CleaningEngineTests.swiftdry-run预演清理后文件仍然存在仅返回正确的计数trash移到废纸篓默认文件被移到~/.Trash字节数与计数都正确permanent永久文件确实消失。以及一系列「真实世界会出错」的场景扫描与清理之间文件已消失 → 优雅跳过并记录错误文件权限不足 → 优雅跳过并列入错误清单一次性提交 10001 项 → 整批安全校验失败什么都不删清理中途取消Task.cancel()→ 尊重取消返回部分结果每次操作都写操作日志日志带 ISO8601 时间戳且路径始终落在~/Library/Logs/MacClean/内、绝不逃逸clean([])空输入 → 计数为零、无错误、无日志。测试夹具让每个测试都远离你的真实主目录一个容易忽略但极其重要的设计测试绝不碰你的真实~/Library。这靠一组夹具fixture完成定义在 Tests/MacCleanTestSupport/TestFixtures.swiftwithTempHome { home in ... }—— 在临时目录里搭出一棵镜像~/Library/...的目录树测完自动清理writeFakeApp(...)—— 在磁盘上合成一个最小的.app包writePlist(...)—— 写出一个测试用的 plistwriteFile(...)—— 按指定大小、修改时间创建一个假文件。FakeHome会镜像 Mac Sai 关心的那部分路径Caches、Logs、Preferences、Application Support、Containers、.Trash等并无论成功还是失败都自动清理。这意味着端到端测试可以真实地「种入文件 → 跑生产扫描 → 跑生产清理 → 断言哪些文件被删、哪些诱饵文件还在」却完全不影响你本机的数据。端到端场景见 Tests/MacCleanTests/EndToEndScenarioTests.swift它调用的是每个生产「清理」按钮都走的同一条CleanActions代码路径。本地运行这套测试想亲眼看看这 862 个测试怎么跑克隆仓库后只需一条命令git clone https://gitcode.com/gh_mirrors/mac/MacSai cd MacSai swift testswift test会一次性跑完全部测试套件。测试支撑代码夹具、时钟等集中在 Tests/MacCleanTestSupport/可复用给任何新增测试。避免的测试反模式这些「诱惑」反而让测试更不值钱docs/TESTING.md 还列出了一份「不要做」清单对新手尤其有参考价值不要整体 mock 文件系统——在临时目录里用真实文件系统行为比 mock 更诚实不要测框架要测你的逻辑——别测FileManager.createDirectory能不能用要测「你的代码是否用对的参数调用了它」不要XCTAssertNotNil(result)就完事——要断言result的实际期望值不要为后端逻辑写快照测试——快照留给 UI逻辑要断言真实字段/值警惕「藏 bug 的测试」——如果一个夹具要费尽心思才能让测试通过那生产代码大概率有值得修的设计问题。小结从「相信安全」到「证明安全」Mac Sai 的测试策略可以浓缩成三句话Sandboxed Logic把业务逻辑从系统依赖里剥出来让 100% 测试成为可能862 个测试按「单元 → 集成 → 端到端」的金字塔铺满夹具保证全程不碰真实主目录安全关键路径SafetyGuard、CleaningEngine追求 100% 覆盖用对抗性用例证明删除引擎的每一步都可被验证。对一款会删除用户文件的工具而言这套测试不是加分项而是它敢叫自己「安全」的底牌。赞分享【免费下载链接】MacSaiMac Sai: the open-source Mac cleaner, optimizer, and malware scanner. A free, Apple-notarized alternative to CleanMyMac, built with Swift 6 and SwiftUI.项目地址https://gitcode.com/gh_mirrors/mac/MacSai点击查看免费下载相关推荐MakeGirlsMoe-Web响应式设计实现适配所有设备的动漫角色生成器终极指南 MakeGirlsMoe Web响应式设计实现适配所有设备的动漫角色生成器终极指南 MakeGirlsMoe Web是一款基于人工智能的动漫角色生成器3分钟快速上手如何用ES-Client轻松管理Elasticsearch集群3分钟快速上手如何用ES Client轻松管理Elasticsearch集群 ES Client是一款专为个人开发者和运维人员打造的 Elasticsearc数据库客户端开发者工具数据可视化Chili3D浏览器上的专业级3D建模工具完整指南Chili3D浏览器上的专业级3D建模工具完整指南 Chili3D是一个基于浏览器的开源3D CAD建模应用让你无需安装复杂软件就能进行专业的3D设计。这个前端图形学3D渲染插件系统创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

信创测试异常场景设计:故障注入与自动化回归实践

信创测试异常场景设计:故障注入与自动化回归实践

做信创测试这几年,最让我意外的从来不是功能跑不通,而是那些只有在异常场景下才冒头的诡异故障。某次适配测试,业务程序在x86环境里连续跑48小时都没事,迁到国产操作系统的ARM服务器后,只要模拟一次突然断电再重启&…

2026/10/10 20:59:44 阅读更多 →
舌苔图像深度学习识别系统实战:从数据预处理到PyQt5 GUI部署

舌苔图像深度学习识别系统实战:从数据预处理到PyQt5 GUI部署

简介:这是一套面向高校计算机相关专业毕业设计与人工智能初学者的舌苔图像深度学习识别系统源码包,围绕医学图像分类任务提供从界面到模型的完整实现。资源共131个文件,以Python源码、模型权重、界面文件、训练日志与论文文档为主&#xff0c…

2026/10/10 20:59:44 阅读更多 →
基于2D切片的肝脏肿瘤分割数据集实战指南

基于2D切片的肝脏肿瘤分割数据集实战指南

简介:本资源为面向医学图像分割任务的Liver肝脏癌症2D数据集,适合从事肝脏及肿瘤分割研究的学生、算法工程师与科研人员使用。原始数据为Liver3d的nii.gz文件,沿x轴切分并剔除前景区域不足0.05的切片,共提取8千余张图像&#xff0…

2026/10/10 20:59:44 阅读更多 →

最新新闻

impeccable:一款面向OpenAPI契约的Python自动化校验工具

impeccable:一款面向OpenAPI契约的Python自动化校验工具

我无法基于当前输入生成符合要求的博文。原因如下:输入中仅提供了项目标题"impeccable",以及空置的“相关热搜词”“最新网络热词”和完全空白的搜索内容块(),未提供任何实质性的项目正文、关键词列表或摘要…

2026/10/10 21:47:36 阅读更多 →
X射线底片焊缝缺陷检测:2647张6类标注数据集,可直接喂给YOLO

X射线底片焊缝缺陷检测:2647张6类标注数据集,可直接喂给YOLO

简介:面向工业X射线底片焊缝缺陷检测的目标检测数据集,涵盖裂纹、未熔合、未渗透等6类焊缝缺陷,共2647张底片图像、4766个真实标注框,适合用于YOLO、Faster R-CNN等目标检测模型的训练与评测。数据采用VOC与YOLO双格式存储&#x…

2026/10/10 21:47:36 阅读更多 →
AI辅助软件测试实战:从脚本生成到日志分析的全流程经验

AI辅助软件测试实战:从脚本生成到日志分析的全流程经验

软件测试这行的工具形态,这几年变化比我入行前十年加起来都大。以前同行碰头聊提效,无非是自动化框架怎么搭、脚本怎么写更稳、CI怎么接;现在问得最多的变成了"你平时用哪个AI工具""Prompt怎么写的""AI生成的脚本你…

2026/10/10 21:47:36 阅读更多 →
开源AI测试工具落地指南:从接口自动化到自愈定位器的实践选型

开源AI测试工具落地指南:从接口自动化到自愈定位器的实践选型

软件测试这个岗位,这两年的变化比过去十年加起来都大。我记得年初帮一个测试组做评审,同事把一份AI生成的接口用例贴出来,从覆盖路径到断言写法看着都像模像样,但一跑就发现大量断言是“凭空捏造”的——它把响应里根本不存在的字…

2026/10/10 21:47:36 阅读更多 →
Inno Setup自定义安装界面:ILSpy反编译+WinForms回调实践

Inno Setup自定义安装界面:ILSpy反编译+WinForms回调实践

简介:一套面向.NET应用开发者的Inno Setup自定义安装界面资源,用于解决安装包界面模板固化、动态配置繁琐的问题。资源基于Inno Setup增强版封装,内置对.NET Framework 4的依赖支持,并将界面逻辑集中在Code.iss脚本中,…

2026/10/10 21:47:36 阅读更多 →
【Claude Code】BMad-Method 多智能体协作实战:PRD 与架构文档一键生成,TaoToken 统一 Key 接入

【Claude Code】BMad-Method 多智能体协作实战:PRD 与架构文档一键生成,TaoToken 统一 Key 接入

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 21:46:35 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:25 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →