Skill

Write Robust iOS Unit Tests

Writes iOS unit tests with XCTest: async/await testing, protocol-based mocking, view controller tests, performance metrics, and parameterized cases.


79
Spark score
out of 100
Updated 7 months ago
Version 1.0.0
Models

Add to Favorites

Why it matters

Ensure the quality and reliability of your iOS applications by implementing comprehensive unit tests. This asset guides you through advanced testing strategies and best practices using the XCTest framework.

Outcomes

What it gets done

01

Implement Arrange-Act-Assert (AAA) pattern for clear test structure.

02

Utilize mocking and dependency injection for isolated testing.

03

Write tests for asynchronous code, error handling, and UI components.

04

Configure test schemes, naming conventions, and CI integration.

Install

Add it to your toolbox

Run in your project directory:

curl -fsSL https://spark.entire.vc/get/vb-ios-unit-test | bash

Overview

iOS Unit Testing Expert

Guides writing iOS unit tests with XCTest - AAA-structured tests, protocol-based mocking, async/await and expectation-based async testing, view controller tests, performance/memory measurement, and parameterized test tables. Reach for this when writing or expanding XCTest coverage for iOS service classes, async code, view controllers, or performance-sensitive logic.

What it does

This skill writes iOS unit tests using the XCTest framework, following the Arrange-Act-Assert pattern with descriptive test_methodName_condition_expectedResult naming. A standard XCTestCase subclass sets up the system-under-test (sut) and its mocked dependencies in setUpWithError() and tears them down in tearDownWithError() to keep tests isolated.

Mocking uses protocol-based dependency injection - a NetworkManagerProtocol with a MockNetworkManager implementation tracking call count and last-passed arguments, and returning a configurable Result (success or failure) to drive different test scenarios. Async/await code is tested directly with async throws test methods, awaiting the system-under-test and asserting on both the returned value and the mock's recorded call state. Error-path tests use do/catch with XCTFail on an unexpected non-throw and type/equality assertions on the caught error.

func test_fetchUser_withValidId_returnsUser() async throws {
    mockNetworkManager.fetchUserResult = .success(expectedUser)
    let result = try await sut.fetchUser(id: "123")
    XCTAssertEqual(result.id, expectedUser.id)
    XCTAssertEqual(mockNetworkManager.fetchUserCallCount, 1)
}

Asynchronous, non-async/await code (like NotificationCenter observers) is tested with XCTestExpectation and wait(for:timeout:). View controller testing instantiates the controller from its storyboard, injects a mock service, calls loadViewIfNeeded(), simulates UI interaction (sendActions(for: .touchUpInside)), and asserts on the mock's recorded calls. Performance and memory testing use measure { } blocks, including XCTMeasureOptions with XCTMemoryMetric() for memory-focused runs. Advanced techniques cover exposing private methods for testing via a testable_ extension method and parameterized testing that iterates a table of input/expected-output pairs (e.g. email validation cases) asserting each with a failure message identifying the specific input.

When to use - and when NOT to

Use this skill when writing or expanding XCTest unit test coverage for an iOS app - testing service classes with mocked dependencies, async/await methods, view controllers, notification-driven code, or performance-sensitive data processing. It applies to both new test suites and adding parameterized or performance tests to an existing suite.

It is not the right tool for full UI/end-to-end testing across multiple screens (XCUITest integration tests are the appropriate tool there) or for platforms other than iOS/Swift, since the framework and mocking patterns are XCTest-specific.

Inputs and outputs

Input: the Swift class, service, or view controller to test and its dependencies (network calls, other services) that need mocking. Output: an XCTestCase subclass with AAA-structured test methods, protocol-based mock implementations tracking calls and arguments, async/await and expectation-based async tests, view controller interaction tests, performance/memory measurement tests, and parameterized test tables for input variation coverage.

Integrations

Built on Apple's XCTest framework (XCTestCase, XCTAssertEqual, XCTestExpectation, measure, XCTMemoryMetric) with @testable import for internal access, and integrates with Xcode test schemes/plans and CI-driven automated test execution with code coverage reporting.

Who it's for

iOS engineers writing or expanding unit test coverage for Swift apps - particularly those testing async/await service code, view controllers, or performance-sensitive logic with protocol-based mocking rather than hitting real network/system dependencies.

FAQ

Common questions

Discussion

Questions & comments ยท 0

Sign In Sign in to leave a comment.