
Swift Testing
- 13 installs
- 9 repo stars
- Updated January 5, 2026
- pluginagentmarketplace/custom-plugin-swift
swift-testing is a Claude Code skill for testing & qa.
About
swift-testing is a Claude Code skill for testing & qa. It helps solo builders move faster with AI-assisted development.
- swift-testing
- Testing & QA
- AI-coding skill
Swift Testing by the numbers
- 13 all-time installs (skills.sh)
- Ranked #1,509 of 2,153 Testing & QA skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/pluginagentmarketplace/custom-plugin-swift --skill swift-testingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 13 |
|---|---|
| repo stars | ★ 9 |
| Last updated | January 5, 2026 |
| Repository | pluginagentmarketplace/custom-plugin-swift ↗ |
How do I helps with testing & qa tasks.?
Helps with testing & qa tasks.
Who is it for?
Best when you're working on testing & qa and need structured help with swift testing.
Skip if: Teams with no testing & qa needs, or anyone wanting a generic chat assistant without this specific workflow.
When should I use this skill?
When you need to helps with testing & qa tasks., or when swift-testing is a claude code skill for testing & qa.
What you get
Structured output aligned to swift-testing: swift-testing, Testing & QA.
Files
Swift Testing Skill
Comprehensive testing strategies for Swift applications using XCTest and Swift Testing framework.
Prerequisites
- Xcode 15+ installed
- Understanding of dependency injection
- Familiarity with async/await
Parameters
parameters:
framework:
type: string
enum: [xctest, swift_testing]
default: swift_testing
test_type:
type: string
enum: [unit, integration, ui, snapshot]
default: unit
coverage_target:
type: number
default: 80
description: Target code coverage percentage
ci_platform:
type: string
enum: [xcode_cloud, github_actions, gitlab_ci, none]
default: github_actionsTopics Covered
Test Frameworks
| Framework | Min Version | Key Features |
|---|---|---|
| XCTest | iOS 2.0+ | XCTestCase, expectations |
| Swift Testing | iOS 17+ / Swift 5.9+ | @Test, #expect, traits |
Test Types
| Type | Scope | Speed |
|---|---|---|
| Unit | Single function/class | Fastest |
| Integration | Multiple components | Medium |
| UI | Full user flows | Slowest |
| Snapshot | Visual regression | Medium |
Testing Patterns
| Pattern | Purpose |
|---|---|
| AAA | Arrange, Act, Assert |
| Given-When-Then | BDD style |
| Test Doubles | Mock, Stub, Spy, Fake |
Code Examples
Swift Testing (iOS 17+ / Swift 5.9+)
import Testing
@testable import MyApp
@Suite("ShoppingCart Tests")
struct ShoppingCartTests {
var cart: ShoppingCart
var mockRepository: MockProductRepository
init() {
mockRepository = MockProductRepository()
cart = ShoppingCart(repository: mockRepository)
}
@Test("adding product increases count")
func addProduct() async throws {
let product = Product(id: "1", name: "Widget", price: 9.99)
cart.add(product)
#expect(cart.items.count == 1)
#expect(cart.items.first?.product == product)
}
@Test("adding same product increases quantity")
func addSameProductTwice() {
let product = Product(id: "1", name: "Widget", price: 9.99)
cart.add(product)
cart.add(product)
#expect(cart.items.count == 1)
#expect(cart.items.first?.quantity == 2)
}
@Test("total calculates correctly")
func calculateTotal() {
cart.add(Product(id: "1", name: "A", price: 10.00))
cart.add(Product(id: "2", name: "B", price: 20.00))
#expect(cart.total == 30.00)
}
@Test("checkout requires non-empty cart", .tags(.checkout))
func checkoutEmptyCart() async {
await #expect(throws: CartError.empty) {
try await cart.checkout()
}
}
@Test("checkout with valid cart", .tags(.checkout))
func checkoutSuccess() async throws {
cart.add(Product(id: "1", name: "Widget", price: 9.99))
mockRepository.checkoutResult = .success(Order(id: "order-1"))
let order = try await cart.checkout()
#expect(order.id == "order-1")
#expect(cart.items.isEmpty)
}
@Test(arguments: [0, 1, 5, 10])
func discountTiers(quantity: Int) {
let discount = cart.calculateDiscount(forQuantity: quantity)
switch quantity {
case 0..<5: #expect(discount == 0)
case 5..<10: #expect(discount == 0.05)
default: #expect(discount == 0.10)
}
}
}XCTest with Async
import XCTest
@testable import MyApp
final class ProductServiceTests: XCTestCase {
var sut: ProductService!
var mockAPI: MockAPIClient!
override func setUp() {
super.setUp()
mockAPI = MockAPIClient()
sut = ProductService(api: mockAPI)
}
override func tearDown() {
sut = nil
mockAPI = nil
super.tearDown()
}
func test_fetchProducts_success() async throws {
// Arrange
let expectedProducts = [Product(id: "1", name: "Test", price: 9.99)]
mockAPI.productsResult = .success(expectedProducts)
// Act
let products = try await sut.fetchProducts()
// Assert
XCTAssertEqual(products, expectedProducts)
XCTAssertTrue(mockAPI.fetchProductsCalled)
}
func test_fetchProducts_networkError_throws() async {
// Arrange
mockAPI.productsResult = .failure(NetworkError.noConnection)
// Act & Assert
do {
_ = try await sut.fetchProducts()
XCTFail("Expected error to be thrown")
} catch {
XCTAssertTrue(error is NetworkError)
}
}
func test_fetchProducts_retries_onTransientError() async throws {
// Arrange
var attempts = 0
mockAPI.onFetchProducts = {
attempts += 1
if attempts < 3 {
throw NetworkError.timeout
}
return [Product(id: "1", name: "Test", price: 9.99)]
}
// Act
_ = try await sut.fetchProductsWithRetry(maxAttempts: 3)
// Assert
XCTAssertEqual(attempts, 3)
}
}Mock Implementation
// Protocol for abstraction
protocol APIClientProtocol {
func fetchProducts() async throws -> [Product]
func createOrder(_ order: CreateOrderRequest) async throws -> Order
}
// Production implementation
final class APIClient: APIClientProtocol {
func fetchProducts() async throws -> [Product] {
// Real implementation
}
func createOrder(_ order: CreateOrderRequest) async throws -> Order {
// Real implementation
}
}
// Test mock
final class MockAPIClient: APIClientProtocol {
var productsResult: Result<[Product], Error> = .success([])
var orderResult: Result<Order, Error> = .success(Order(id: "mock"))
var fetchProductsCalled = false
var fetchProductsCallCount = 0
var createOrderCalled = false
var lastOrderRequest: CreateOrderRequest?
var onFetchProducts: (() async throws -> [Product])?
func fetchProducts() async throws -> [Product] {
fetchProductsCalled = true
fetchProductsCallCount += 1
if let handler = onFetchProducts {
return try await handler()
}
return try productsResult.get()
}
func createOrder(_ order: CreateOrderRequest) async throws -> Order {
createOrderCalled = true
lastOrderRequest = order
return try orderResult.get()
}
func reset() {
productsResult = .success([])
orderResult = .success(Order(id: "mock"))
fetchProductsCalled = false
fetchProductsCallCount = 0
createOrderCalled = false
lastOrderRequest = nil
onFetchProducts = nil
}
}UI Testing with Page Object Pattern
import XCTest
// Page Object
struct LoginPage {
let app: XCUIApplication
var usernameField: XCUIElement {
app.textFields["username"]
}
var passwordField: XCUIElement {
app.secureTextFields["password"]
}
var loginButton: XCUIElement {
app.buttons["login"]
}
var errorMessage: XCUIElement {
app.staticTexts["errorMessage"]
}
func login(username: String, password: String) {
usernameField.tap()
usernameField.typeText(username)
passwordField.tap()
passwordField.typeText(password)
loginButton.tap()
}
func waitForLogin(timeout: TimeInterval = 5) -> Bool {
!usernameField.waitForExistence(timeout: timeout)
}
}
// UI Test
final class LoginUITests: XCTestCase {
var app: XCUIApplication!
var loginPage: LoginPage!
override func setUp() {
super.setUp()
continueAfterFailure = false
app = XCUIApplication()
app.launchArguments = ["--uitesting", "--reset-state"]
app.launch()
loginPage = LoginPage(app: app)
}
func test_login_withValidCredentials_navigatesToHome() {
loginPage.login(username: "testuser", password: "password123")
XCTAssertTrue(loginPage.waitForLogin())
XCTAssertTrue(app.tabBars["mainTabBar"].exists)
}
func test_login_withInvalidCredentials_showsError() {
loginPage.login(username: "wrong", password: "wrong")
XCTAssertTrue(loginPage.errorMessage.waitForExistence(timeout: 5))
XCTAssertEqual(loginPage.errorMessage.label, "Invalid credentials")
}
}GitHub Actions CI
name: Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: macos-14
steps:
- uses: actions/checkout@v4
- name: Select Xcode
run: sudo xcode-select -s /Applications/Xcode_15.2.app
- name: Build and Test
run: |
xcodebuild test \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 15,OS=17.2' \
-resultBundlePath TestResults.xcresult \
-enableCodeCoverage YES \
CODE_SIGNING_ALLOWED=NO
- name: Upload Results
uses: actions/upload-artifact@v3
if: failure()
with:
name: test-results
path: TestResults.xcresult
- name: Coverage Report
run: |
xcrun xccov view --report TestResults.xcresultTroubleshooting
Common Issues
| Issue | Cause | Solution |
|---|---|---|
| Flaky tests | Shared state | Add setUp/tearDown cleanup |
| Async timeout | Missing fulfillment | Call fulfill() or increase timeout |
| UI element not found | Wrong identifier | Check accessibilityIdentifier |
| Mock not working | Wrong initialization | Verify dependency injection |
| Coverage low | Untested paths | Add edge case tests |
Debug Tips
// Print XCUIElement hierarchy
print(app.debugDescription)
// Wait for condition
let exists = element.waitForExistence(timeout: 5)
// Take screenshot on failure
let screenshot = XCUIScreen.main.screenshot()
let attachment = XCTAttachment(screenshot: screenshot)
attachment.lifetime = .keepAlways
add(attachment)Validation Rules
validation:
- rule: test_naming
severity: info
check: Use descriptive test names (test_method_condition_result)
- rule: one_assertion
severity: info
check: Prefer one logical assertion per test
- rule: no_test_interdependence
severity: error
check: Tests must not depend on each otherUsage
Skill("swift-testing")Related Skills
swift-fundamentals- Code to testswift-concurrency- Testing async codeswift-architecture- Testable architecture
# Swift Testing Configuration
framework: XCTest
parallel_testing: true
code_coverage: true
minimum_coverage: 80
test_targets:
- UnitTests
- IntegrationTests
- UITests
import XCTest
@testable import {{MODULE_NAME}}
final class {{CLASS_NAME}}Tests: XCTestCase {
var sut: {{CLASS_NAME}}!
override func setUp() {
super.setUp()
sut = {{CLASS_NAME}}()
}
override func tearDown() {
sut = nil
super.tearDown()
}
func test_{{METHOD_NAME}}_{{SCENARIO}}_{{EXPECTATION}}() {
// Given
// When
// Then
}
}
Swift Testing Guide
XCTest Basics
import XCTest
@testable import MyApp
final class UserServiceTests: XCTestCase {
func test_createUser_withValidData_succeeds() {
// Given
let service = UserService()
let userData = UserData(name: "John", email: "john@example.com")
// When
let result = service.create(userData)
// Then
XCTAssertNotNil(result)
XCTAssertEqual(result?.name, "John")
}
}Async Testing
func test_fetchUsers_returnsData() async throws {
let service = UserService()
let users = try await service.fetchUsers()
XCTAssertFalse(users.isEmpty)
}Mocking
protocol UserRepository {
func fetchUser(id: UUID) async throws -> User
}
class MockUserRepository: UserRepository {
var stubbedUser: User?
func fetchUser(id: UUID) async throws -> User {
guard let user = stubbedUser else {
throw TestError.notFound
}
return user
}
}Testing Patterns
Given-When-Then
func test_login_withValidCredentials_returnsUser() {
// Given - Setup
let auth = AuthService()
let credentials = Credentials(email: "test@example.com", password: "password")
// When - Action
let result = auth.login(with: credentials)
// Then - Assert
XCTAssertNotNil(result.user)
XCTAssertNil(result.error)
}Test Naming Convention
test_<method>_<scenario>_<expectation>
Examples:
- test_validate_withEmptyEmail_returnsFalse
- test_calculateTotal_withDiscount_appliesPercentage
- test_fetchData_whenOffline_returnsCache#!/bin/bash
# Generate Coverage Report
RESULT_BUNDLE=$1
xcrun xccov view --report "$RESULT_BUNDLE" --json > coverage.json
echo "✅ Coverage report generated: coverage.json"
#!/bin/bash
# Run Swift Tests with Coverage
SCHEME=$1
if [ -z "$SCHEME" ]; then
echo "Usage: run-tests.sh <scheme-name>"
exit 1
fi
xcodebuild test \
-scheme "$SCHEME" \
-destination 'platform=iOS Simulator,name=iPhone 15' \
-enableCodeCoverage YES \
-resultBundlePath TestResults.xcresult
echo "✅ Tests complete. Results in TestResults.xcresult"
Related skills
FAQ
What does swift-testing do?
swift-testing is a Claude Code skill for testing & qa.
When should I use swift-testing?
When you need to helps with testing & qa tasks., or when swift-testing is a claude code skill for testing & qa.
What are the main capabilities?
swift-testing; Testing & QA; AI-coding skill.