360 Secure SkillHub
360 安全技能中心

swiftdata-testing

针对 SwiftData 应用编写和审查单元/集成测试,提供内存 ModelContainer 夹具、Mock 仓库、@ModelActor 隔离、Decimal 金额断言与内容哈希去重测试指引,并指出迁移计划与纯内存配置混用等已知陷阱。

akshaypimprikar
热度 0.00
最近更新 2026-10-18 22:57:55
分类:开发依赖:纯提示词应用场景:代码生成 / 代码审查

安装技能

复制下面的话术发给你的 Agent,它会通过 secure-skills 检索并安装该技能。

执行命令安装此 skill: npx secure-skills-cli add akshaypimprikar/ios-swiftdata-testing-agent-skill/swiftdata-testing
Metadata
name
swiftdata-testing
description
Writes and reviews SwiftData test code — in-memory ModelContainer fixtures, mock repository patterns, @ModelActor test isolation, Decimal money-value assertions, and content-hash dedup testing. Use when writing or reviewing unit/integration tests for a SwiftData-backed app.
license
MIT
metadata
{"author":"Akshay Pimprikar","version":"1.0"}

Write and review SwiftData test code so it runs in isolation, never touches the device's persistent store, and catches the failure modes specific to @Model, @ModelActor, and money-typed data. Report only genuine problems — do not nitpick or invent issues.

Test-writing process:

  1. For repository/integration tests, use references/model-container-fixtures.md for the in-memory ModelContainer setup.
  2. For ViewModel unit tests, use references/mock-repositories.md — never construct a real ModelContainer just to unit test a ViewModel.
  3. If the code under test uses @ModelActor, use references/model-actor-testing.md for actor-isolation-safe test patterns.
  4. If the model stores currency/money values, use references/decimal-money-values.md — Decimal requires different assertion patterns than Double.
  5. If the code deduplicates records via a content hash (e.g. CSV/API import), use references/import-hash-dedup.md.

If doing partial work, load only the relevant reference files.

Core Instructions

  • Target Swift 6.2+ with the Testing framework (@Suite, @Test, #expect, #require) — not XCTest, for unit and integration tests.
  • Every test that touches SwiftData must use isStoredInMemoryOnly: true. A test that writes to the real persistent store is not a unit test — it's a device-state mutation with a #Test label on it.
  • Never share a ModelContext or ModelContainer instance across tests. Build a fresh one per @Test — SwiftData containers are cheap, and cross-test state leakage produces the kind of intermittent failure that looks like flakiness but is actually a fixture bug.
  • Domain/business-logic tests should not need a ModelContainer at all. If a test imports SwiftData just to instantiate a value it never persists or fetches, that's a sign business logic isn't cleanly separated from the persistence layer yet — flag it rather than writing around it.
  • Never move a @Model instance across an actor boundary — not even in test code. Pass PersistentIdentifier or a value-type DTO and re-fetch inside the target actor.

Output Format

If the user asks for a review, organize findings by file. For each issue:

  1. State the file and relevant line(s).
  2. Name the rule being violated.
  3. Show a brief before/after code fix.

Skip files with no issues. End with a prioritized summary of the most impactful fixes.

If the user asks you to write or fix tests, follow the same rules above but make the changes directly instead of returning a findings report.

Known Gotcha: migrationPlan + isStoredInMemoryOnly don't mix

Applying a SchemaMigrationPlan to an in-memory-only ModelConfiguration causes save() to fail — sometimes silently, sometimes non-deterministically depending on device load, which makes it look flaky rather than broken. An in-memory store starts fresh on every launch, so there is nothing to migrate.

// Before — breaks intermittently under isStoredInMemoryOnly
let container = try ModelContainer(
    for: schema,
    migrationPlan: AppMigrationPlan.self,
    configurations: [config]
)

// After — branch on isStoredInMemoryOnly before applying the migration plan
if config.isStoredInMemoryOnly {
    return try ModelContainer(for: schema, configurations: [config])
}
return try ModelContainer(for: schema, migrationPlan: AppMigrationPlan.self, configurations: [config])

This applies to both @main app-launch code (for UI test targets) and any test helper that happens to reuse the app's production container builder instead of a dedicated in-memory one.