Comprehensive testing guide for iOS and Swift applications, written at principal engineer level. Contains 44 rules across 8 categories, prioritized by impact to guide test architecture decisions, test authoring patterns, and CI infrastructure.
Clinic Architecture Contract (iOS 26 / Swift 6.2)
All guidance in this skill assumes the clinic modular MVVM-C architecture:
Feature modules import Domain + DesignSystem only (never Data, never sibling features)
App target is the convergence point and owns DependencyContainer, concrete coordinators, and Route Shell wiring
Domain stays pure Swift and defines models plus repository, *Coordinating, ErrorRouting, and AppError contracts
Data owns SwiftData/network/sync/retry/background I/O and implements Domain protocols
Read/write flow defaults to stale-while-revalidate reads and optimistic queued writes
ViewModels call repository protocols directly (no default use-case/interactor layer)
When to Apply
Reference these guidelines when:
Writing new unit tests or UI tests for iOS apps
Designing testable architecture with dependency injection
Testing async/await, actors, and Combine publishers
Setting up snapshot testing or visual regression suites
Configuring CI pipelines, test plans, and parallel execution
Rule Categories by Priority
Priority
Category
Impact
Prefix
1
Test Architecture & Testability
CRITICAL
arch-
2
Unit Testing Fundamentals
CRITICAL
unit-
3
Test Doubles & Isolation
HIGH
mock-
4
Async & Concurrency Testing
HIGH
async-
5
SwiftUI Testing
MEDIUM-HIGH
swiftui-
6
UI & Acceptance Testing
MEDIUM
ui-
7
Snapshot & Visual Testing
MEDIUM
snap-
8
Test Reliability & CI
LOW-MEDIUM
ci-
Quick Reference
1. Test Architecture & Testability (CRITICAL)
arch-protocol-dependencies - Depend on protocols, not concrete types
arch-constructor-injection - Use constructor injection over service locators
arch-test-target-separation - Separate unit and UI test targets
arch-testable-import - Use @testable import sparingly
arch-single-responsibility-tests - One assertion concept per test
arch-arrange-act-assert - Structure tests as Arrange-Act-Assert
2. Unit Testing Fundamentals (CRITICAL)
unit-swift-testing-framework - Use Swift Testing over XCTest for new tests
unit-parameterized-tests - Use parameterized tests for input variations
unit-descriptive-test-names - Name tests after the behavior they verify
unit-expect-over-assert - Use #expect and #require over XCTAssert
unit-require-preconditions - Use #require for test preconditions
unit-test-suites - Organize related tests into suites
unit-test-tags - Use tags to categorize cross-cutting tests
3. Test Doubles & Isolation (HIGH)
mock-protocol-based-mocks - Create mocks from protocols, not subclasses
mock-spy-for-verification - Use spies to verify interactions
mock-stub-return-values - Use stubs for deterministic return values
mock-avoid-over-mocking - Avoid mocking value types and simple logic
mock-fake-for-integration - Use in-memory fakes for integration tests
mock-dependency-container - Use a dependency container for test configuration
4. Async & Concurrency Testing (HIGH)
async-await-directly - Await async functions directly in tests
async-confirmation - Use confirmation() for callback-based APIs
async-mainactor-isolation - Test MainActor-isolated code on MainActor
async-actor-testing - Test actor state through async interface
async-task-cancellation - Test task cancellation paths explicitly
5. SwiftUI Testing (MEDIUM-HIGH)
swiftui-test-observable-models - Test @Observable models as plain objects
swiftui-environment-injection - Inject environment dependencies for tests
swiftui-preview-as-test - Use previews as visual smoke tests
swiftui-view-model-extraction - Extract logic from views into testable models
swiftui-binding-testing - Test binding behavior with @Bindable
6. UI & Acceptance Testing (MEDIUM)
ui-accessibility-identifiers - Use accessibility identifiers for element queries
ui-page-object-pattern - Encapsulate screens in page objects
ui-launch-arguments - Configure test state via launch arguments
ui-wait-for-elements - Wait for elements instead of using sleep()
ui-test-user-journeys - Test complete user journeys, not individual screens
ui-reset-state-between-tests - Reset app state between UI tests
7. Snapshot & Visual Testing (MEDIUM)
snap-swift-snapshot-testing - Use swift-snapshot-testing for visual regression
snap-device-matrix - Snapshot across device sizes and traits
snap-named-references - Use named snapshot references for clarity
snap-inline-snapshots - Use inline snapshots for non-image assertions
8. Test Reliability & CI (LOW-MEDIUM)
ci-test-plans - Use Xcode Test Plans for environment configurations
ci-parallel-execution - Enable parallel test execution
ci-flaky-test-quarantine - Quarantine flaky tests instead of disabling them
ci-deterministic-test-data - Use deterministic test data over random generation
ci-coverage-thresholds - Set coverage thresholds for critical paths
How to Use
Read individual reference files for detailed explanations and code examples:
Section definitions - Category structure and impact levels
Rule template - Template for adding new rules
Reference Files
File
Description
references/_sections.md
Category definitions and ordering
assets/templates/_template.md
Template for new rules
metadata.json
Version and reference information
1---2name: ios-testing3description: iOS Testing Best Practices4---5# iOS Testing Best Practices67Comprehensive testing guide for iOS and Swift applications, written at principal engineer level. Contains 44 rules across 8 categories, prioritized by impact to guide test architecture decisions, test authoring patterns, and CI infrastructure.8910## Clinic Architecture Contract (iOS 26 / Swift 6.2)1112All guidance in this skill assumes the clinic modular MVVM-C architecture:1314- Feature modules import `Domain` + `DesignSystem` only (never `Data`, never sibling features)15- App target is the convergence point and owns `DependencyContainer`, concrete coordinators, and Route Shell wiring16- `Domain` stays pure Swift and defines models plus repository, `*Coordinating`, `ErrorRouting`, and `AppError` contracts17- `Data` owns SwiftData/network/sync/retry/background I/O and implements Domain protocols18- Read/write flow defaults to stale-while-revalidate reads and optimistic queued writes19- ViewModels call repository protocols directly (no default use-case/interactor layer)2021## When to Apply2223Reference these guidelines when:24- Writing new unit tests or UI tests for iOS apps25- Designing testable architecture with dependency injection26- Testing async/await, actors, and Combine publishers27- Setting up snapshot testing or visual regression suites28- Configuring CI pipelines, test plans, and parallel execution2930## Rule Categories by Priority3132| Priority | Category | Impact | Prefix |33|----------|----------|--------|--------|34| 1 | Test Architecture & Testability | CRITICAL | `arch-` |35| 2 | Unit Testing Fundamentals | CRITICAL | `unit-` |36| 3 | Test Doubles & Isolation | HIGH | `mock-` |37| 4 | Async & Concurrency Testing | HIGH | `async-` |38| 5 | SwiftUI Testing | MEDIUM-HIGH | `swiftui-` |39| 6 | UI & Acceptance Testing | MEDIUM | `ui-` |40| 7 | Snapshot & Visual Testing | MEDIUM | `snap-` |41| 8 | Test Reliability & CI | LOW-MEDIUM | `ci-` |4243## Quick Reference4445### 1. Test Architecture & Testability (CRITICAL)4647- [`arch-protocol-dependencies`](references/arch-protocol-dependencies.md) - Depend on protocols, not concrete types48- [`arch-constructor-injection`](references/arch-constructor-injection.md) - Use constructor injection over service locators49- [`arch-test-target-separation`](references/arch-test-target-separation.md) - Separate unit and UI test targets50- [`arch-testable-import`](references/arch-testable-import.md) - Use @testable import sparingly51- [`arch-single-responsibility-tests`](references/arch-single-responsibility-tests.md) - One assertion concept per test52- [`arch-arrange-act-assert`](references/arch-arrange-act-assert.md) - Structure tests as Arrange-Act-Assert5354### 2. Unit Testing Fundamentals (CRITICAL)5556- [`unit-swift-testing-framework`](references/unit-swift-testing-framework.md) - Use Swift Testing over XCTest for new tests57- [`unit-parameterized-tests`](references/unit-parameterized-tests.md) - Use parameterized tests for input variations58- [`unit-descriptive-test-names`](references/unit-descriptive-test-names.md) - Name tests after the behavior they verify59- [`unit-expect-over-assert`](references/unit-expect-over-assert.md) - Use #expect and #require over XCTAssert60- [`unit-require-preconditions`](references/unit-require-preconditions.md) - Use #require for test preconditions61- [`unit-test-suites`](references/unit-test-suites.md) - Organize related tests into suites62- [`unit-test-tags`](references/unit-test-tags.md) - Use tags to categorize cross-cutting tests6364### 3. Test Doubles & Isolation (HIGH)6566- [`mock-protocol-based-mocks`](references/mock-protocol-based-mocks.md) - Create mocks from protocols, not subclasses67- [`mock-spy-for-verification`](references/mock-spy-for-verification.md) - Use spies to verify interactions68- [`mock-stub-return-values`](references/mock-stub-return-values.md) - Use stubs for deterministic return values69- [`mock-avoid-over-mocking`](references/mock-avoid-over-mocking.md) - Avoid mocking value types and simple logic70- [`mock-fake-for-integration`](references/mock-fake-for-integration.md) - Use in-memory fakes for integration tests71- [`mock-dependency-container`](references/mock-dependency-container.md) - Use a dependency container for test configuration7273### 4. Async & Concurrency Testing (HIGH)7475- [`async-await-directly`](references/async-await-directly.md) - Await async functions directly in tests76- [`async-confirmation`](references/async-confirmation.md) - Use confirmation() for callback-based APIs77- [`async-mainactor-isolation`](references/async-mainactor-isolation.md) - Test MainActor-isolated code on MainActor78- [`async-actor-testing`](references/async-actor-testing.md) - Test actor state through async interface79- [`async-task-cancellation`](references/async-task-cancellation.md) - Test task cancellation paths explicitly8081### 5. SwiftUI Testing (MEDIUM-HIGH)8283- [`swiftui-test-observable-models`](references/swiftui-test-observable-models.md) - Test @Observable models as plain objects84- [`swiftui-environment-injection`](references/swiftui-environment-injection.md) - Inject environment dependencies for tests85- [`swiftui-preview-as-test`](references/swiftui-preview-as-test.md) - Use previews as visual smoke tests86- [`swiftui-view-model-extraction`](references/swiftui-view-model-extraction.md) - Extract logic from views into testable models87- [`swiftui-binding-testing`](references/swiftui-binding-testing.md) - Test binding behavior with @Bindable8889### 6. UI & Acceptance Testing (MEDIUM)9091- [`ui-accessibility-identifiers`](references/ui-accessibility-identifiers.md) - Use accessibility identifiers for element queries92- [`ui-page-object-pattern`](references/ui-page-object-pattern.md) - Encapsulate screens in page objects93- [`ui-launch-arguments`](references/ui-launch-arguments.md) - Configure test state via launch arguments94- [`ui-wait-for-elements`](references/ui-wait-for-elements.md) - Wait for elements instead of using sleep()95- [`ui-test-user-journeys`](references/ui-test-user-journeys.md) - Test complete user journeys, not individual screens96- [`ui-reset-state-between-tests`](references/ui-reset-state-between-tests.md) - Reset app state between UI tests9798### 7. Snapshot & Visual Testing (MEDIUM)99100- [`snap-swift-snapshot-testing`](references/snap-swift-snapshot-testing.md) - Use swift-snapshot-testing for visual regression101- [`snap-device-matrix`](references/snap-device-matrix.md) - Snapshot across device sizes and traits102- [`snap-named-references`](references/snap-named-references.md) - Use named snapshot references for clarity103- [`snap-inline-snapshots`](references/snap-inline-snapshots.md) - Use inline snapshots for non-image assertions104105### 8. Test Reliability & CI (LOW-MEDIUM)106107- [`ci-test-plans`](references/ci-test-plans.md) - Use Xcode Test Plans for environment configurations108- [`ci-parallel-execution`](references/ci-parallel-execution.md) - Enable parallel test execution109- [`ci-flaky-test-quarantine`](references/ci-flaky-test-quarantine.md) - Quarantine flaky tests instead of disabling them110- [`ci-deterministic-test-data`](references/ci-deterministic-test-data.md) - Use deterministic test data over random generation111- [`ci-coverage-thresholds`](references/ci-coverage-thresholds.md) - Set coverage thresholds for critical paths112113## How to Use114115Read individual reference files for detailed explanations and code examples:116117- [Section definitions](references/_sections.md) - Category structure and impact levels118- [Rule template](assets/templates/_template.md) - Template for adding new rules119120## Reference Files121122| File | Description |123|------|-------------|124| [references/_sections.md](references/_sections.md) | Category definitions and ordering |125| [assets/templates/_template.md](assets/templates/_template.md) | Template for new rules |126| [metadata.json](metadata.json) | Version and reference information |
Run npx skillmds@latest add comeonoliver/ios-testing in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
iOS Testing Best Practices It is listed under Coding & Dev Tools on SkillMD.
This skill has not completed SkillMD's automated safety review yet. Independent scanners report: SkillSpector: PASS, Skill Scanner: PASS. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
ComeOnOliver (@comeonoliver) published this skill. Their other Agent Skills are listed on their SkillMD profile.