【免费下载链接】appA native iOS companion app for Radarr and Sonarr instances.项目地址https://gitcode.com/gh_mirrors/app154/app点击查看免费下载Ruddarr 是一款开源的 iOS 原生 companion app伴侣应用用于在手机上管理 Radarr 和 Sonarr 影视媒体库实例。要让它稳定可靠项目搭建了一套完整的测试与 CI持续集成体系通过可切换的 Mock 依赖隔离真实服务器、用 Preview Content 目录下的 JSON Fixture 还原真实接口数据再配合 20 个自动化测试文件与三阶段 CI 脚本保证每次构建都经过验证。本文带你完整走读这套实践。为什么需要 Mock离线测试 Radarr/Sonarr 应用测试一个依赖私有 API 的 iOS 伴侣应用最大的难题是本地开发机不一定连得上你的 Radarr/Sonarr 实例。Ruddarr 的解法是把所有网络调用抽象成一组闭包再提供.live真实请求和.mock模拟数据两套实现一行代码即可切换。API 抽象层一切皆闭包核心在 API.swift整个网络层被拆成RadarrAPI、SonarrAPI、InstanceAPI三个结构体每个端点都是可替换的Sendable闭包例如var fetch: Sendable (Instance) async throws - [Movie]真实实现APILive.swift 调用/api/v3/movie等接口模拟实现APIMock.swift 返回本地 Fixture 数据依赖注入中心Dependencies.swift 中的全局let dependencies: Dependencies .live本地一键切换 Mock 模式在 Ruddarr.swift 的init()中DEBUG 构建下留有两行被注释的代码// dependencies.api .mock // dependencies.cloudkit .mock取消注释注释即可让 App 完全脱离网络和 iCloud 运行——CloudKit 同步同样有 mock 分支见 InstanceWebhook.swift。Preview Content 预览 Fixture26 个 JSON 还原真实数据Mock 实现并不硬编码假数据而是通过loadPreviewData函数APIMock.swift从 Ruddarr/Preview Content/ 目录读取 JSON 文件解码而成。这些 Fixture 同时也是 Xcode Canvas 预览的 Development Assets在 project.pbxproj 中配置了DEVELOPMENT_ASSET_PATHS。主力 Fixture 清单Fixture 文件内容movies.json电影库完整列表约 1.6 MB含多语言替代标题、海报series.json剧集库完整列表movie-releases.json / series-releases.json可下载资源搜索结果calendar-movies.json / calendar-episodes.json日历页上映数据radarr-history.json / sonarr-history.json活动历史事件root-folders.json、quality-profiles.json、disk-space.json、tags.json、system-status.json实例系统信息movie-queue.json / series-queue.json下载队列任务Mock 层还做了两个贴心设计见 modifyCalendarMovies 等函数模拟网络延迟每个闭包内用Task.sleep睡 1–3 秒让加载骨架屏、进度态都能被观察到日期实时化把日历 Fixture 中的固定日期按“距今天数”动态平移保证日历页永远有“即将上映”的内容种子实例seed-instances 本地联调想连真实服务器又嫌配置麻烦项目提供 seed-instances.example.json 模板复制为seed-instances.json填入 URL 与 API Key 后在 DEBUG 构建的 Settings → Instances 中使用Seed Instances即可批量导入实例约定详见 CLAUDE.md 的 Local instances 一节。Xcode Preview免费造出离线、失败、超时 3 种 UI 状态Mock 的“闭包可替换”设计还有一个隐藏福利每个#Preview里可以直接覆盖单个闭包零成本造出各种异常 UI。MoviesView.swift 就是范例#Preview(Offline) { dependencies.api.radarr.fetch { _ in throw API.Error.notConnectedToInternet } return ContentView().withAppState() }同样的套路还覆盖了Failure服务端错误和Timeout私网 IP 超时场景——这正是“预览 Fixture Mock 依赖”配合的威力UI 设计师和开发者不需要连服务器就能看到所有状态。自动化测试清单Swift Testing 框架下的 20 个测试文件Tests/ 目录共 20 个测试文件、约 3000 行断言全部采用 Swift 官方新框架Swift Testingimport TestingTest#expect。测试 Target 为Tests.xctest挂在共享 Scheme 中见 Ruddarr.xcscheme。按主题分组的测试清单测试文件验证目标PlaceholderTests.swift本地化字符串模板%占位符替换内存安全版String(format:)BreakableTests.swift资源标题长字符串换行插入零宽空格、最小尾缀保护FormatStringParityTests.swift / HexEncodingTests.swiftSwift 6 格式化迁移的字节级等价性以旧实现为 oracle 对照DateDecodingStrategyTests.swiftiso8601extended日期解码策略与旧ISO8601DateFormatter行为一致LossyDecodingTests.swiftSonarr 返回languages: [null]时数组丢空元素而非整体失败DecodingErrorDiagnosticsTests.swift / InstanceDecodeDiagnosticsTests.swift解码失败诊断Sentry 上报门控与无 PII 的取证摘要InstanceWireFormatTests.swift锁死 iCloud 同步instances值的跨版本 JSON 格式防止旧版本客户端把库写空RouteTableTests.swift / NetworkInterfacesTests.swift / ResolverProbeTests.swift / InstanceResolverTests.swift网络路由表解析、LAN/Tailscale 分类、实例 URL 选择器状态机RequestTimeoutTests.swift / RequestDiagnosticsTests.swift本地/远程差异化超时预算、失败请求环形缓冲PrivacyTests.swift诊断报告中 URL 脱敏掩码域名、保留子网段FormatBytesTests.swift / RootFolderLabelTests.swift / ChangelogParserTests.swift / RuddarrTests.swift字节格式化、根文件夹标签消歧、更新日志解析、本地化参数替换三条值得学习的测试约定纯函数优先几乎每个测试都先测“纯逻辑”路由、掩码、解析器把系统依赖隔离到不可测的壳层里Oracle 对照法重构时保留旧实现作参照如 DateDecodingStrategyTests.swift 中的legacy函数断言新旧输出字节级一致Fixture 冻结契约用固化 JSON 锁死 iCloud 同步格式注释中甚至写明了“为什么必须存在”InstanceWireFormatTests.swift 头注释CI 三阶段流水线ci_scripts 详解ci_scripts/ 下三个 Shell 脚本挂在构建流程的“克隆后 / 构建前 / 构建后”三个钩子上。克隆后ci_post_clone.sh 同步多语言翻译ci_post_clone.sh 负责把 Crowdin 平台上的翻译拉进仓库构建校验CROWDIN_TOKEN用 Homebrew 安装crowdin与yq均带 5 次线性退避重试的retry包装从 crowdin.yml 读取导出语言列表并把 Crowdin 语言码转成 Apple 语言码zh-CN→zh-Hans、es-ES→esmacOS 平台用plutil动态写入Info.plist的CFBundleLocalizations用jq从三个.xcstrings字符串目录中删除未导出的语言避免把半成品翻译打进发布包构建前ci_pre_xcodebuild.sh 注入发布密钥ci_pre_xcodebuild.sh 做两件小事跳过 SwiftLint 插件指纹校验然后从密钥APNS_SECRET注入 Info.plist 的APNsKey推送证书并写入CI_BRANCH供版本标记使用——缺失任何一个都会让流水线快速失败。构建后ci_post_xcodebuild.sh 上传 dSYMci_post_xcodebuild.sh 安装sentry-cli并执行sentry-cli debug-files upload把归档CI_ARCHIVE_PATH中的 dSYM 符号表上传到 Sentry保证线上崩溃报告能还原 Swift 堆栈。CI 实际执行的 xcodebuild 命令按 CLAUDE.md 记录CI 分别用以下命令跑 iOS 与 macOS 测试均禁用代码签名# iOS 模拟器测试 xcodebuild test -scheme Ruddarr -skipPackagePluginValidation \ -destination platformiOS Simulator,nameiPhone 17 Pro \ CODE_SIGNING_ALLOWEDNO CODE_SIGN_IDENTITY CODE_SIGNING_REQUIREDNO \ MACOSX_DEPLOYMENT_TARGET26.0macOS 侧把-destination换成platformmacOS即可CodeQL 静态分析则用xcodebuild build加相同参数。上手清单5 分钟搭起本地验证环境打开 Ruddarr.xcodeproj选中共享 SchemeRuddarr无需真实实例取消注释 Ruddarr.swift 中的dependencies.api .mock跑起完全离线的数据浏览 Ruddarr/Views/ 中任意带#Preview的文件在 Canvas 中切换 Offline / Failure / Timeout 三个变体需要联调真实服务器时复制 seed-instances.example.json 填写后使用Seed Instances本地跑一遍xcodebuild test -scheme Ruddarr命令见上文确认 20 个测试文件全绿小结Ruddarr 的测试体系可以浓缩为三句话用闭包抽象 API、用 Fixture 喂数据、用 CI 卡质量。Mock 依赖让预览和调试彻底摆脱服务器Preview Content 的 26 个 JSON 让假数据足够逼真而 CI 的三阶段脚本加上 Swift Testing 自动化测试则把“翻译同步、密钥注入、符号上传、行为回归”全部自动化。这套实践对任何依赖外部 API 的 iOS 项目都非常有参考价值。 赞分享【免费下载链接】appA native iOS companion app for Radarr and Sonarr instances.项目地址https://gitcode.com/gh_mirrors/app154/app点击查看免费下载相关推荐IBAnalyzer 单元测试之道依赖注入、Stub 与 Mock 的完整实践清单IBAnalyzer 单元测试之道依赖注入、Stub 与 Mock 的完整实践清单 IBAnalyzer 是一款无需运行 App 即可检查 xib 与 stololPing 桌面应用怎么测测试与 CI 实践完整清单lolPing 桌面应用怎么测测试与 CI 实践完整清单 lolPing https://link.gitcode.com/i/bdf7b26b2f037ac用 pytest Fixture 组合重构 FastAPI SQLModel 测试Client Fixture 与依赖覆盖的完整实践用 pytest Fixture 组合重构 FastAPI SQLModel 测试Client Fixture 与依赖覆盖的完整实践 导读 本文基于 SQORM数据库后端上一篇Oh My Posh 功能更新解析Accordion 折叠段、跨段模板属性与 PowerShell 迁移指南下一篇如何快速用好 Qwen3.8-27B 的图片理解从数学题到扫描件解析的完整实战流水线创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考