- 只有用户在当前任务中明确要求添加测试,才允许新增或扩写测试,包括测试文件、suite、用例、断言、 fixture、mock、helper 和仅为测试引入的生产代码 hook;修复 bug、新增功能、修改复杂逻辑和回归 风险都不构成授权。
- 未获授权时可以运行和分析现有测试,认为需要补充时只在结果中提建议;获授权后优先更新现有用例, 遵循最小范围,不为测试简单实现增加生产抽象、mock 或 hook。
- 新增服务时,必须新增该服务专属的验证测试文件。服务验证可以依赖实现者本机的 CLI、登录态、密钥或 其他配置;实现者必须在自己的开发环境中运行并通过该验证。此类环境依赖测试不要求每位开发者或 CI 持续运行,应通过非默认 test plan 或 Xcode 的精确测试选择运行,且不得将其误认为默认离线回归测试。
- 优先运行直接覆盖变更风险的检查,影响范围不明确时再扩大;只修改已授权的测试与 fixture,不把 未运行、失败或环境阻塞的检查写成通过。
- 测试目录按领域对应源码模块,Swift 测试以
Easydict/Swift/为映射根,例如Service/OpenAI/对应EasydictTests/Service/OpenAI/;跨模块测试按主要业务归属放置,现有目录按任务范围渐进调整。 - 每个测试文件聚焦一个主要被测类型或行为领域,最多声明一个
@Suite;接近文件规模限制时按职责 拆分 suite 和 fixture,保留原有覆盖和标签、actor 隔离、共享状态恢复、串行边界。独立 suite 的.serialized不提供跨 suite 串行保证。 - 单文件 helper 保持局部,同领域共享工具就近放置,跨目录复用的 fixture 或工具放入
EasydictTests/Support/<Domain>/,资源放入对应测试资源目录。 - 新增、移动或删除由 Xcode 管理的源码文件或运行时资源时,同步
Easydict.xcodeproj/project.pbxproj中的 group、文件和 build phase 引用,测试文件同时同步测试 target 的 Sources,删除文件不保留悬空引用。仓库治理 Markdown、plan、history、skill、参考资料 和docs/下的公共 Markdown 不需要工程引用,除非作为运行时资源发布。
根据变更需要证明的结果选择最小且充分的验证,不按变更行数设置硬阈值。
- 纯治理 Markdown、plan、history、注释,以及不进入 Xcode 构建图的脚本或配置,只运行相应静态 检查:Markdown 的格式、相对链接、锚点和规则语义检查。
- 生产源码、工程/workspace、target、build setting、build phase、依赖、entitlement、Info.plist
或运行时资源发生实质变化时,运行覆盖受影响配置的
xcodebuild build;修复 bug、修改可测试 行为或测试源码及其 target 引用时,运行覆盖相应行为、suite 或方法的xcodebuild test。 xcodebuild build只证明构建集成;相同配置的成功测试已覆盖编译,不重复运行 build,测试未覆盖 的 Release、Archive、签名或其他配置另行验证。重复运行兼容的测试时先build-for-testing,再 用test-without-building,前者本身不构成测试通过证据。- 每次变更运行
git diff --check;对变更的.xcstrings或 JSON 运行jq -e .,对变更的 Shell 脚本运行bash -n。 - 并发判据是构建目录而不是构建入口:同一 workspace 与同一 DerivedData 的并发构建,无论来自
Xcode IDE 还是
xcodebuild,都会互相破坏增量状态和 build database;DerivedData 不同可以并行。 - 因此 agent 运行
xcodebuild时始终显式指定-derivedDataPath,指向按 checkout 派生、与 Xcode 默认目录不相交的~/Library/Developer/Xcode/DerivedData/Easydict-Agent/<checkout-id>;损坏时 删除该目录重建,不切换到 Xcode 默认 DerivedData。 - Agent 构建、运行和测试沿用项目当前配置的 bundle ID,不为隔离验证额外覆盖
PRODUCT_BUNDLE_IDENTIFIER,除非用户明确要求;编译缓存通过独立 DerivedData 隔离。
xcodebuild test和test-without-building会启动独立的 Easydict 测试宿主;同 bundle ID 本身不是禁止并行的依据。运行前检查测试及宿主启动逻辑涉及的共享资源冲突(如偏好、文件、 固定端口、全局快捷键或设备),必要时隔离或串行,不默认退出用户的 Xcode 实例。- 界面验证默认复用已有实例,不使用
open -n(用户明确要求多实例验证除外);未获授权 不退出或替换用户实例。 - 启动前后按 bundle ID、产物路径核对 PID 和实例数,区分测试宿主与非预期重复实例。 出现异常或界面自动化失败时暂停继续启动,仅查询进程排查,避免界面操作意外拉起应用。
- 结束时仅退出本任务创建的实例并恢复临时设置;需要恢复原应用时,按原路径只启动一次, 再通过不会启动应用的进程查询确认。
# 每个 checkout 一个 agent 专用 DerivedData,与 Xcode 默认目录互不相交
set -o pipefail
checkout_id="$(git rev-parse --show-toplevel | sed -e "s|^$HOME/||" -e 's|^\.||' -e 's|/|_|g')"
agent_dd="$HOME/Library/Developer/Xcode/DerivedData/Easydict-Agent/$checkout_id"
# 构建
xcodebuild build \
-workspace Easydict.xcworkspace \
-scheme Easydict \
-derivedDataPath "$agent_dd" | xcbeautify
# 运行测试
xcodebuild test \
-workspace Easydict.xcworkspace \
-scheme Easydict \
-derivedDataPath "$agent_dd" | xcbeautify
# 构建可复用的测试产物
xcodebuild build-for-testing \
-workspace Easydict.xcworkspace \
-scheme Easydict \
-derivedDataPath "$agent_dd" | xcbeautify
# 复用已构建产物运行指定 suite 或方法,-only-testing 支持 <Suite> 与 <Suite>/<test>
xcodebuild test-without-building \
-workspace Easydict.xcworkspace \
-scheme Easydict \
-derivedDataPath "$agent_dd" \
-only-testing:EasydictTests/UtilityFunctionsTests | xcbeautifyxcbeautify 依赖 pipefail 才能保留 xcodebuild 的真实退出状态。重建时只删除当前 checkout 的
agent_dd,不动 Xcode 默认目录或其他 checkout。