This skill should be used when the user asks to "generate unit tests", "create UI tests", "add snapshot tests", "test SwiftUI views", "generate test doubles", "increase test coverage", or needs guidance on iOS testing patterns and test suite generation.
From ios-dev-toolkitnpx claudepluginhub nbkm8y5/claude-plugins --plugin ios-dev-toolkitThis skill uses the workspace's default tool permissions.
references/testing-patterns.mdscripts/generate_mock_factories.pyscripts/generate_test_doubles.pySearches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Guides implementation of event-driven hooks in Claude Code plugins using prompt-based validation and bash commands for PreToolUse, Stop, and session events.
Generate comprehensive, maintainable test suites for iOS applications following testing pyramid best practices.
test_[unitOfWork]_[scenario]_[expectedBehavior]Generate tests based on component type:
Generate unit tests for my TipCalculator class
Create UI tests for the login flow using screen objects
Generate snapshot tests for ProductCard view across devices
Generate snapshot tests, state tests, interaction tests, and accessibility tests.
Pattern:
func test_view_initialState_matchesSnapshot() throws {
let view = ContentView(viewModel: .mock())
assertSnapshot(matching: view, as: .image(layout: .device(config: .iPhone13)))
}
func test_view_whenButtonTapped_callsViewModel() throws {
let viewModel = ContentViewModelSpy()
let view = ContentView(viewModel: viewModel)
try view.inspect().find(button: "Refresh").tap()
XCTAssertTrue(viewModel.refreshCalled)
}
Script: Use scripts/generate_view_tests.py for batch generation
Generate comprehensive tests for state management, data loading, user actions, and validation.
Pattern:
func test_loadData_success_updatesItems() async {
// Given
mockService.itemsToReturn = [Item.mock(), Item.mock()]
// When
await sut.loadData()
// Then
XCTAssertEqual(sut.items.count, 2)
XCTAssertFalse(sut.isLoading)
XCTAssertNil(sut.error)
}
Generate calculation tests, validation tests, and edge case coverage.
Pattern:
func test_calculateTip_withValidAmount_returnsCorrectTip() {
let result = sut.calculateTip(amount: 100.0, percentage: 0.15)
XCTAssertEqual(result, 15.0, accuracy: 0.01)
}
Generate request building, response handling, error handling, and retry logic tests.
Pattern:
func test_fetch_withValidResponse_decodesData() async throws {
mockSession.data = try JSONEncoder().encode(User.mock())
mockSession.response = HTTPURLResponse(statusCode: 200)
let result: User = try await sut.fetch(.getUser(id: 123))
XCTAssertEqual(result.id, expectedUser.id)
}
Generate CRUD operation tests with in-memory CoreData store.
Pattern:
func test_createItem_savesSuccessfully() throws {
let item = try sut.createItem(name: "Test Item")
XCTAssertNotNil(item)
XCTAssertFalse(item.objectID.isTemporaryID)
}
final class MockDataService: DataServiceProtocol {
var itemsToReturn: [Item] = []
var errorToThrow: Error?
func fetchItems() async throws -> [Item] {
if let error = errorToThrow { throw error }
return itemsToReturn
}
}
final class DataServiceSpy: DataServiceProtocol {
var fetchItemsCalled = false
var fetchItemsCallCount = 0
var capturedItems: [Item] = []
}
final class StubURLSession: URLSessionProtocol {
var data: Data?
var response: URLResponse?
var error: Error?
}
Script: Use scripts/generate_test_doubles.py to create mocks/spies/stubs
Generate reusable test data with sensible defaults:
extension User {
static func mock(
id: UUID = UUID(),
name: String = "Test User",
email: String = "test@example.com"
) -> User {
User(id: id, name: name, email: email)
}
}
Script: Use scripts/generate_mock_factories.py
Generate page object pattern for maintainable UI tests:
class LoginScreen {
let app: XCUIApplication
var emailTextField: XCUIElement { app.textFields["email-field"] }
var loginButton: XCUIElement { app.buttons["login-button"] }
func login(email: String, password: String) {
emailTextField.tap()
emailTextField.typeText(email)
// ...
loginButton.tap()
}
}
Script: Use scripts/generate_screen_objects.py
Generate snapshot tests across devices and states:
func test_productCard_allStates() {
let states: [(name: String, product: Product)] = [
("available", .mock(stock: 10)),
("out-of-stock", .mock(stock: 0)),
("on-sale", .mock(onSale: true))
]
for (name, product) in states {
assertSnapshot(matching: ProductCard(product: product),
as: .image(layout: .device(config: .iPhone13)),
named: name)
}
}
Generate performance benchmarks:
func test_sortLargeDataSet_performance() {
let items = (0..<10000).map { _ in Item.mock() }
measure {
let _ = items.sorted { $0.price < $1.price }
}
}
Generate VoiceOver, Dynamic Type, and keyboard navigation tests:
func test_allInteractiveElements_haveAccessibilityLabels() {
let buttons = app.buttons.allElementsBoundByIndex
for button in buttons {
XCTAssertFalse(button.label.isEmpty, "Button missing accessibility label")
}
}
Generate end-to-end flow tests:
func test_completeCheckout_fromCartToConfirmation() async throws {
// Given: Items in cart
try await cartService.addItem(Item.mock(price: 29.99))
// When: Process payment
let paymentResult = try await paymentService.processPayment(...)
let order = try await orderService.createOrder(...)
// Then: Verify order created and cart cleared
XCTAssertEqual(order.status, .confirmed)
let clearedCart = try await cartService.getCart()
XCTAssertTrue(clearedCart.items.isEmpty)
}
YourAppTests/
├── UnitTests/
│ ├── ViewModels/
│ ├── Services/
│ ├── BusinessLogic/
│ └── Models/
├── IntegrationTests/
├── SnapshotTests/
│ └── __Snapshots__/
├── PerformanceTests/
├── Helpers/
│ ├── Mocks/
│ └── Builders/
└── UITests/
└── ScreenObjects/
func test_publisher_emitsExpectedValues() {
var values: [String] = []
let expectation = expectation(description: "Publisher")
viewModel.$text
.dropFirst()
.sink { values.append($0); expectation.fulfill() }
.store(in: &cancellables)
wait(for: [expectation], timeout: 1.0)
XCTAssertEqual(values, ["First", "Second"])
}
func test_asyncFunction_throwsError() async {
do {
try await sut.fetchData()
XCTFail("Expected error")
} catch {
XCTAssertEqual(error as? DataError, .networkFailure)
}
}
func test_closure_doesNotCauseCycle() {
weak var weakViewModel: ContentViewModel?
autoreleasepool {
let viewModel = ContentViewModel()
weakViewModel = viewModel
viewModel.onComplete = { [weak viewModel] in
viewModel?.handleCompletion()
}
}
XCTAssertNil(weakViewModel)
}
When generating tests, provide:
For detailed patterns and examples, see:
references/testing-patterns.md - Comprehensive pattern libraryreferences/test-doubles-guide.md - Mock/Spy/Stub implementationsreferences/snapshot-testing-guide.md - Visual regression testing