Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Generate test templates for unit tests, integration tests, and UI tests using Swift Testing and XCTest. Use when adding tests to iOS/macOS apps.
.claude/skills/rshankras-test-generator/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | 60% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 92% | 0% |
| case-19 | ✗→✓ | ▲ Improved | 183% | 0% |
| case-15 | ✓→✗ | ▼ Worse | 129% | 0% |
| case-06 | ✓→✓ | = Same ✓ | 100% | 0% |
Generate test templates for unit tests, integration tests, and UI tests in iOS/macOS apps.
Use this skill when the user:
@Test, #expect, @Suite)What tests do you need?
|
+-- Unit tests for business logic
| +-- Swift Testing (@Test, #expect) -- recommended for iOS 16+
| +-- XCTest -- for iOS 13-15 support or existing XCTest projects
|
+-- Integration tests (component interactions)
| +-- Protocol-based mocks with dependency injection
|
+-- UI tests
| +-- XCUITest with Screen Object pattern
|
+-- Snapshot/preview tests
+-- PreviewSnapshots or swift-snapshot-testingSearch for existing test infrastructure:
Glob: **/*Tests.swift, **/*Tests/**/*.swift, **/*Spec.swift
Grep: "import XCTest" or "import Testing" or "@Suite" or "@Test"
Grep: "MockItemRepository" or "protocol.*Repository" or "class Mock"If existing tests are found:
If a test target already exists:
Grep: "ViewModel" or "Reducer" or "UseCase" or "Repository" or "Service"
Glob: **/*ViewModel.swift, **/*Reducer.swift, **/*Repository.swiftThis determines which test templates to generate (ViewModel tests, Reducer tests, etc.).
Tests/UnitTests/
├── ViewModelTests/
│ └── ItemViewModelTests.swift
├── ServiceTests/
│ └── APIClientTests.swift
└── RepositoryTests/
└── ItemRepositoryTests.swiftTests/UITests/
├── Screens/
│ └── HomeScreenTests.swift
├── Flows/
│ └── OnboardingFlowTests.swift
└── Helpers/
└── TestHelpers.swiftswiftimport Testing @testable import YourApp @Suite("Item ViewModel Tests") struct ItemViewModelTests { @Test("loads items successfully") func loadsItems() async throws { let mockRepository = MockItemRepository() let viewModel = ItemViewModel(repository: mockRepository) await viewModel.loadItems() #expect(viewModel.items.count == 3) #expect(viewModel.isLoading == false) } @Test("handles empty state") func handlesEmptyState() async { let mockRepository = MockItemRepository(items: []) let viewModel = ItemViewModel(repository: mockRepository) await viewModel.loadItems() #expect(viewModel.items.isEmpty) #expect(viewModel.showEmptyState) } }
swift@Test("validates email format", arguments: [ ("valid@email.com", true), ("invalid", false), ("no@tld", false), ("test@domain.co.uk", true) ]) func validatesEmail(email: String, isValid: Bool) { #expect(EmailValidator.isValid(email) == isValid) }
swiftimport XCTest @testable import YourApp final class ItemViewModelTests: XCTestCase { var sut: ItemViewModel! var mockRepository: MockItemRepository! override func setUp() { super.setUp() mockRepository = MockItemRepository() sut = ItemViewModel(repository: mockRepository) } override func tearDown() { sut = nil mockRepository = nil super.tearDown() } func testLoadsItems() async throws { await sut.loadItems() XCTAssertEqual(sut.items.count, 3) XCTAssertFalse(sut.isLoading) } }
swift@Suite("ViewModel Tests") struct ViewModelTests { @Test("state transitions correctly") func stateTransitions() async { let vm = ItemViewModel(repository: MockItemRepository()) #expect(vm.state == .idle) await vm.loadItems() #expect(vm.state == .loaded) } @Test("error handling") func errorHandling() async { let failingRepo = MockItemRepository(shouldFail: true) let vm = ItemViewModel(repository: failingRepo) await vm.loadItems() #expect(vm.state == .error) #expect(vm.errorMessage != nil) } }
swift@Test("fetches data asynchronously") func fetchesData() async throws { let service = APIService() let result = try await service.fetchItems() #expect(result.count > 0) } @Test("times out appropriately") func timesOut() async { await #expect(throws: TimeoutError.self) { try await withTimeout(seconds: 1) { try await Task.sleep(for: .seconds(5)) } } }
swiftprotocol ItemRepository { func fetchItems() async throws -> [Item] func saveItem(_ item: Item) async throws } final class MockItemRepository: ItemRepository { var items: [Item] = [] var shouldFail = false var saveCallCount = 0 func fetchItems() async throws -> [Item] { if shouldFail { throw TestError.mockFailure } return items } func saveItem(_ item: Item) async throws { saveCallCount += 1 items.append(item) } }
swiftimport XCTest final class HomeScreen { let app: XCUIApplication init(app: XCUIApplication) { self.app = app } var itemList: XCUIElement { app.collectionViews["itemList"] } var addButton: XCUIElement { app.buttons["addItem"] } func tapItem(at index: Int) { itemList.cells.element(boundBy: index).tap() } func addNewItem(title: String) { addButton.tap() app.textFields["itemTitle"].tap() app.textFields["itemTitle"].typeText(title) app.buttons["save"].tap() } }
In Xcode:
YourAppTests)bash# Command line xcodebuild test -scheme YourApp -destination 'platform=iOS Simulator,name=iPhone 16' # With coverage xcodebuild test -scheme YourApp -enableCodeCoverage YES
| # | Mistake | Why It's Wrong | Fix | |---|---------|---------------|-----| | 1 | Testing implementation details instead of behavior | Tests break on every refactor, providing no safety net | Test public API and observable outcomes, not internal state | | 2 | Sharing mutable state between tests | Tests pass individually but fail when run together (order-dependent) | Create fresh instances in each test; use init() in @Suite structs or setUp() in XCTest | | 3 | Using XCTAssertTrue(result != nil) instead of XCTUnwrap | Failure message is useless ("XCTAssertTrue failed") with no context | Use let value = try XCTUnwrap(result) or #expect(result != nil) with Swift Testing | | 4 | Not testing error paths | Only happy-path coverage; errors crash in production | Always test with shouldFail = true mocks and verify error state | | 5 | Real network calls in unit tests | Tests are slow, flaky, and fail offline | Use protocol-based mocks; reserve real network calls for integration test schemes |
Before finishing test generation, verify:
loadsItemsSuccessfully not testLoadItems)async throws (Swift Testing) or async throws with expectations (XCTest)#expect(items.count == 3) not #expect(!items.isEmpty)try #require() (Swift Testing) or XCTUnwrap (XCTest)xcodebuild test or Xcode test navigatorOther measured skills in the registry, with their headline benchmark lift.