Use when adding automated tests to CocoaPods libraries using test specs. Covers test spec configuration, app host requirements, and testing patterns that integrate with pod lib lint validation.
Install
npx skillscat add thebushidocollective/han/cocoapods-test-specs Install via the SkillsCat registry.
SKILL.md
CocoaPods - Test Specs
Integrate automated tests into your CocoaPods library that run during validation.
What Are Test Specs?
Test specs define test targets that CocoaPods builds and runs automatically during pod lib lint and pod spec lint validation.
Benefits
- Automatic Testing: Tests run during every lint validation
- Confidence: Validates library works as expected before publishing
- CI Integration: Consistent testing across all environments
- Documentation: Tests serve as usage examples
Basic Test Spec
Pod::Spec.new do |spec|
spec.name = 'MyLibrary'
spec.version = '1.0.0'
# Main library source
spec.source_files = 'Source/**/*.swift'
# Test spec
spec.test_spec 'Tests' do |test_spec|
test_spec.source_files = 'Tests/**/*.swift'
# Test dependencies
test_spec.dependency 'Quick', '~> 7.0'
test_spec.dependency 'Nimble', '~> 12.0'
end
endApp Host Requirements
Tests Without App Host
spec.test_spec 'Tests' do |test_spec|
test_spec.source_files = 'Tests/**/*.swift'
# Unit tests that don't need app environment
test_spec.requires_app_host = false # Default
endTests With App Host
spec.test_spec 'UITests' do |test_spec|
test_spec.source_files = 'Tests/UITests/**/*.swift'
# Tests that need app environment (UIKit, storyboards, etc.)
test_spec.requires_app_host = true
test_spec.dependency 'MyLibrary'
endMultiple Test Specs
Pod::Spec.new do |spec|
spec.name = 'MyLibrary'
# Unit tests (no app host)
spec.test_spec 'UnitTests' do |unit|
unit.source_files = 'Tests/Unit/**/*.swift'
unit.dependency 'Quick'
unit.dependency 'Nimble'
end
# Integration tests (with app host)
spec.test_spec 'IntegrationTests' do |integration|
integration.source_files = 'Tests/Integration/**/*.swift'
integration.requires_app_host = true
integration.dependency 'MyLibrary'
end
# UI tests (with app host)
spec.test_spec 'UITests' do |ui|
ui.source_files = 'Tests/UI/**/*.swift'
ui.requires_app_host = true
ui.dependency 'MyLibrary'
ui.ios.frameworks = 'XCTest'
end
endPlatform-Specific Test Specs
spec.test_spec 'Tests' do |test_spec|
# Shared test files
test_spec.source_files = 'Tests/Shared/**/*.swift'
# iOS-specific tests
test_spec.ios.source_files = 'Tests/iOS/**/*.swift'
test_spec.ios.frameworks = 'XCTest'
# macOS-specific tests
test_spec.osx.source_files = 'Tests/macOS/**/*.swift'
test_spec.osx.frameworks = 'XCTest'
endTest Dependencies
Testing Frameworks
spec.test_spec 'Tests' do |test_spec|
# Quick/Nimble (BDD style)
test_spec.dependency 'Quick', '~> 7.0'
test_spec.dependency 'Nimble', '~> 12.0'
# Or traditional XCTest (no additional dependencies)
test_spec.frameworks = 'XCTest'
endMocking Frameworks
spec.test_spec 'Tests' do |test_spec|
test_spec.source_files = 'Tests/**/*.swift'
# OCMock for Objective-C
test_spec.dependency 'OCMock', '~> 3.9'
# Cuckoo for Swift
test_spec.dependency 'Cuckoo', '~> 2.0'
# MockingKit for Swift
test_spec.dependency 'MockingKit', '~> 1.0'
endTest Resources
spec.test_spec 'Tests' do |test_spec|
test_spec.source_files = 'Tests/**/*.swift'
# Test resources (JSON fixtures, images, etc.)
test_spec.resources = 'Tests/Fixtures/**/*'
# Or test resource bundle
test_spec.resource_bundles = {
'MyLibraryTests' => ['Tests/Fixtures/**/*']
}
endScheme Configuration
spec.test_spec 'Tests' do |test_spec|
test_spec.source_files = 'Tests/**/*.swift'
# Scheme name (optional - auto-generated if not specified)
test_spec.scheme = { :name => 'MyLibrary-Tests' }
# Code coverage
test_spec.scheme = {
:code_coverage => true
}
endTesting Subspecs
Pod::Spec.new do |spec|
spec.name = 'MyLibrary'
# Core subspec
spec.subspec 'Core' do |core|
core.source_files = 'Source/Core/**/*.swift'
# Tests for Core subspec
core.test_spec 'Tests' do |test_spec|
test_spec.source_files = 'Tests/Core/**/*.swift'
test_spec.dependency 'Quick'
test_spec.dependency 'Nimble'
end
end
# Networking subspec
spec.subspec 'Networking' do |net|
net.source_files = 'Source/Networking/**/*.swift'
net.dependency 'MyLibrary/Core'
# Tests for Networking subspec
net.test_spec 'Tests' do |test_spec|
test_spec.source_files = 'Tests/Networking/**/*.swift'
test_spec.dependency 'OHHTTPStubs', '~> 9.0'
end
end
endCommon Testing Patterns
XCTest Pattern
spec.test_spec 'Tests' do |test_spec|
test_spec.source_files = 'Tests/**/*.swift'
test_spec.frameworks = 'XCTest'
# No additional dependencies needed
# Tests use import XCTest
endQuick/Nimble Pattern
spec.test_spec 'Tests' do |test_spec|
test_spec.source_files = 'Tests/**/*.swift'
test_spec.dependency 'Quick', '~> 7.0'
test_spec.dependency 'Nimble', '~> 12.0'
# Tests use QuickSpec and expect()
endNetwork Mocking Pattern
spec.test_spec 'NetworkTests' do |test_spec|
test_spec.source_files = 'Tests/Network/**/*.swift'
# Mock HTTP responses
test_spec.dependency 'OHHTTPStubs', '~> 9.0'
# Or URLProtocol-based mocking
test_spec.dependency 'Mocker', '~> 3.0'
endSnapshot Testing Pattern
spec.test_spec 'SnapshotTests' do |test_spec|
test_spec.source_files = 'Tests/Snapshots/**/*.swift'
test_spec.requires_app_host = true
# Snapshot testing framework
test_spec.dependency 'SnapshotTesting', '~> 1.15'
# Reference images
test_spec.resources = 'Tests/Snapshots/__Snapshots__/**/*'
endRunning Tests
During Lint Validation
# Tests run automatically
pod lib lint
# Skip tests (faster, but not recommended)
pod lib lint --skip-tests
# Verbose test output
pod lib lint --verboseStandalone Test Execution
# In Example app
cd Example
pod install
xcodebuild test -workspace MyLibrary.xcworkspace -scheme MyLibrary-TestsBest Practices
Directory Structure
MyLibrary/
├── MyLibrary.podspec
├── Source/
│ └── MyLibrary/
├── Tests/
│ ├── Unit/ # Unit tests
│ ├── Integration/ # Integration tests
│ ├── UI/ # UI tests
│ └── Fixtures/ # Test data
└── Example/
└── MyLibraryExample.xcodeprojTest Organization
# Organize by test type
spec.test_spec 'UnitTests' do |unit|
unit.source_files = 'Tests/Unit/**/*.swift'
unit.dependency 'Quick'
unit.dependency 'Nimble'
end
spec.test_spec 'IntegrationTests' do |integration|
integration.source_files = 'Tests/Integration/**/*.swift'
integration.requires_app_host = true
endDependency Management
spec.test_spec 'Tests' do |test_spec|
# Only test dependencies here
test_spec.dependency 'Quick'
test_spec.dependency 'Nimble'
# Main library dependencies go in main spec
# Not in test spec
endAnti-Patterns
Don't
❌ Skip tests during validation
pod lib lint --skip-tests # Defeats purpose of test specs❌ Mix test and production code
spec.source_files = 'Source/**/*.swift', 'Tests/**/*.swift' # BAD❌ Include test dependencies in main spec
# In main spec
spec.dependency 'Quick' # Should be in test_spec only❌ Use requires_app_host unnecessarily
spec.test_spec 'Tests' do |test_spec|
# Pure unit tests don't need app host
test_spec.requires_app_host = true # Slower, unnecessary
endDo
✅ Run tests during every validation
pod lib lint # Includes tests by default✅ Separate test and production code
spec.source_files = 'Source/**/*.swift'
spec.test_spec 'Tests' do |test_spec|
test_spec.source_files = 'Tests/**/*.swift'
end✅ Keep test dependencies in test spec
spec.test_spec 'Tests' do |test_spec|
test_spec.dependency 'Quick' # Only for tests
end✅ Use app host only when needed
spec.test_spec 'Tests' do |test_spec|
# Only if tests need UIKit, storyboards, etc.
test_spec.requires_app_host = true
endExample: Complete Test Spec Setup
Pod::Spec.new do |spec|
spec.name = 'MyAwesomeLibrary'
spec.version = '1.0.0'
spec.summary = 'An awesome library'
spec.homepage = 'https://github.com/username/MyAwesomeLibrary'
spec.license = { :type => 'MIT', :file => 'LICENSE' }
spec.authors = { 'Your Name' => 'email@example.com' }
spec.source = { :git => 'https://github.com/username/MyAwesomeLibrary.git', :tag => spec.version.to_s }
spec.ios.deployment_target = '13.0'
spec.swift_versions = ['5.7', '5.8', '5.9']
spec.source_files = 'Source/**/*.swift'
# Unit tests
spec.test_spec 'UnitTests' do |unit|
unit.source_files = 'Tests/Unit/**/*.swift'
unit.dependency 'Quick', '~> 7.0'
unit.dependency 'Nimble', '~> 12.0'
end
# Integration tests with app host
spec.test_spec 'IntegrationTests' do |integration|
integration.source_files = 'Tests/Integration/**/*.swift'
integration.requires_app_host = true
integration.dependency 'OHHTTPStubs', '~> 9.0'
end
endRelated Skills
- cocoapods-podspec-fundamentals
- cocoapods-subspecs-organization
- cocoapods-publishing-workflow