Skip to content
Agentmart
Submit a tool

ios-testing-strategy

Step-by-step procedure for adding tests to existing Swift/iOS code, whether untested legacy code or new TDD work.

Skill by apexbymanish

IndexedMIT
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/apexbymanish-ios-testing-strategy

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Step-by-step procedure for adding tests to existing Swift/iOS code, whether untested legacy code or new TDD work. Use when asked to "add test coverage", "write tests for this", "make this testable", or when starting TDD on new Swift code.

Use cases: testing, writing

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/ios-testing-strategy

What's inside

Skill name
ios-testing-strategy
Description
Step-by-step procedure for adding tests to existing Swift/iOS code, whether untested legacy code or new TDD work. Use when asked to "add test coverage", "write tests for this", "make this testable", or when starting TDD on new Swift code.
License
MIT
Instructions
97 lines in SKILL.md · view on GitHub

Files (1)

  • SKILL.md

SKILL.md (first lines)

# iOS Testing Strategy

A concrete procedure, not just principles. Follow these steps in order.

## 1. Identify the seams

Before writing a single test, find (or create) the seams that let you
substitute real dependencies with test doubles:

- Networking, persistence (Core Data/SwiftData contexts), date/time,
  and any singleton (`.shared`) are the usual suspects.
- If the code under test reaches a singleton directly, introduce a
  protocol and inject it — don't test through the singleton.

```swift
protocol UserRepository {
    func fetchUser(id: String) async throws -> User
}

final class LiveUserRepository: UserRepository { /* real network call */ }

final class ProfileViewModel {
    private let repository: UserRepository
    init(repository: UserRepository) { self.repository = repository }
}
```

If the class under test currently hardcodes `LiveUserRepository()`
internally, that's the first fix: add the initializer parameter above
(default it to the live implementation so call sites don't all need to
change at once).

## 2. Write a test double, not a framework

A hand-written struct/class conforming to the protocol is almost always
enough. Reach for a mocking library only if the project already has one.

```swift
final class StubUserRepository: UserRepository {
    var result: Result<User, Error> = .success(.mock)
    func fetchUser(id: String) async throws -> User { try result.get() }
}
```

## 3. Write the test against behavior, not implementation

Assert on outputs and observable state changes, not on which private
methods got called.

```swift
@Test func profileLoadShowsFetchedUserName() async throws {
    let repository = StubUserRepository()
    repository.result = .success(User(id: "1", name: "Ada"))
    let viewModel = ProfileViewModel(repository: repository)

    await viewModel.load(id: "1")

    #expect(viewModel.displayName == "Ada")
}
```

Use Swift Testing (`@Test`, `#expect`) for new code in projects on Swift
5.10+ / Xcode 16+. Use XCTest for projects that haven't adopted Swift
Testing yet — check the existing test target before picking one; don't
mix frameworks in the same target without a reason.

## 4. Verify red before green

Before implementing the fix/feature, run the test and confirm it fails
for the *expected* reason (not a compile error, not a setup bug):

Run: `xcodebuild test -scheme <Scheme> -destination 'platform=iOS Simulator,name=iPhone 16' -only-testing:<Target>/<TestClass>/<testName>`

Then implement the minimal code to pass, and re-run the same command to
confirm green.

## 5. Prioritize by risk, not by percentage

Coverage percentage is a lagging indicator. Prioritize, in order:

1. Business logic with branching (pricing, eligibility, state machines).
2. Anything that has broken in production before.
3. Public API of a module other code depends on.
4. Pure UI layout code is usually not worth unit testing — that's what
   `ios-ui-test-engineer` and snapshot tests are for.

## 6. What NOT to test

- Don't test that a SwiftUI `View`'s `body` produces particular view
  types — that's an implementation detail and breaks on every refactor.
- Don't test third-party framework behavior (e.g. that `URLSession`
  actually makes a network call) — test that *your code* calls it
  correctly, via the seam from step 1.
- Don't write a test for a private method by making it internal/public
  just to reach it — test through the public behavior that uses it.

From apexbymanish/claude-ai-agents-ios, MIT.

More from apexbymanish/claude-ai-agents-ios

Signals

Stars
0
Forks
0
Open issues
0
Last commit (this folder)
Aug 28, 2026 (2 months ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from apexbymanish

Cite this page

ios-testing-strategy skill. Agent Mart. https://agentmart.dev/skills/apexbymanish-ios-testing-strategy (last updated 2026-10-24)