Quick Testing Framework Deployment & Usage Guide
Prerequisites
Before installing Quick, ensure you have the following:
- macOS with Xcode installed (latest stable version recommended)
- Swift Toolchain matching your project's requirements (see compatibility table below)
- CocoaPods (1.10.0+) or Swift Package Manager (included with Xcode)
- Nimble (companion matcher framework—installed automatically with Quick)
Swift Version Compatibility
| Swift version | Quick version | Nimble version |
|---|---|---|
| Swift 5.2+ | v3.0.0 or later | v9.0.0 or later |
| Swift 4.2 / Swift 5 | v1.3.2 or later | v7.3.2 or later |
| Swift 3 / Swift 4 | v1.0.0 or later | v5.0.0 or later |
Critical: Quick uses private Xcode APIs and must never be included in your App Store submission binary. Only link Quick to your test targets.
Installation
Method 1: Swift Package Manager (Recommended)
Add Quick and Nimble to your Package.swift dependencies:
// swift-tools-version:5.3
import PackageDescription
let package = Package(
name: "YourProject",
dependencies: [
.package(url: "https://github.com/Quick/Quick.git", from: "7.0.0"),
.package(url: "https://github.com/Quick/Nimble.git", from: "12.0.0"),
],
targets: [
.testTarget(
name: "YourProjectTests",
dependencies: [
"Quick",
"Nimble",
.target(name: "YourProject")
]
)
]
)
Method 2: CocoaPods
Add to your Podfile:
use_frameworks!
target "YourApp" do
# Your app dependencies
target 'YourApp_Tests' do
inherit! :search_paths
pod 'Quick'
pod 'Nimble'
end
end
Then run:
pod install
Method 3: Git Submodules
git submodule add https://github.com/Quick/Quick.git
git submodule add https://github.com/Quick/Nimble.git
Drag Quick.xcodeproj and Nimble.xcodeproj into your Xcode workspace. Link Quick.framework and Nimble.framework only to your test target (not the main app target).
Configuration
Basic Test Target Setup
Create a new Swift file in your test target ending in Spec.swift or Tests.swift:
import Quick
import Nimble
import YourProject
class TableOfContentsSpec: QuickSpec {
override class func spec() {
// Your tests go here
}
}
Advanced Configuration (QCKConfiguration)
Create a QuickConfiguration subclass to configure global hooks and filters:
import Quick
class TestConfiguration: QuickConfiguration {
override class func configure(_ configuration: QCKConfiguration) {
// Run before entire test suite
configuration.beforeSuite {
// Setup code
}
// Run after entire test suite
configuration.afterSuite {
// Teardown code
}
// Custom inclusion filters
configuration.include { example in
// Return true to include this example
return example.name.contains("Critical")
}
}
}
Shared Examples
Define reusable test behaviors in your configuration or spec files:
// In your spec or configuration
sharedExamples("a shared behavior") { (sharedExampleContext: SharedExampleContext) in
it("has some behavior") {
let context = sharedExampleContext()
expect(context["value"]).toNot(beNil())
}
}
// Usage in spec
itBehavesLike("a shared behavior") { ["value": 42] }
Build & Run
Writing Tests
Quick uses behavior-driven development syntax with describe, context, and it:
import Quick
import Nimble
class CalculatorSpec: QuickSpec {
override class func spec() {
describe("Calculator") {
var calculator: Calculator!
beforeEach {
calculator = Calculator()
}
context("when adding numbers") {
it("returns the sum") {
expect(calculator.add(2, 3)).to(equal(5))
}
it("handles negative numbers") {
expect(calculator.add(-2, 3)).to(equal(1))
}
}
context("when dividing") {
it("throws on divide by zero") {
expect { try calculator.divide(1, 0) }.to(throwError())
}
}
}
}
}
Running Tests in Xcode
- Open your
.xcworkspace(if using CocoaPods) or.xcodeproj - Select your test scheme (usually
YourAppTestsorYourAppUITests) - Use Cmd+U to run all tests, or click the diamond icon next to individual tests in the Test Navigator
Running from Command Line
# Run all tests
xcodebuild test -workspace YourApp.xcworkspace -scheme YourApp -destination 'platform=iOS Simulator,name=iPhone 14'
# Run specific test bundle
xcodebuild test -project YourApp.xcodeproj -scheme YourAppTests -destination 'platform=macOS'
Async Testing
For async/await tests, use AsyncSpec:
import Quick
import Nimble
class AsyncNetworkSpec: AsyncSpec {
override class func spec() {
describe("Network client") {
it("fetches data asynchronously") {
let client = NetworkClient()
let data = try await client.fetchData()
expect(data).toNot(beEmpty())
}
}
}
}
Deployment
CI/CD Integration
Quick tests integrate with standard Xcode testing. Example GitHub Actions workflow:
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Run tests
run: xcodebuild test -scheme YourApp -destination 'platform=iOS Simulator,name=iPhone 14' -enableCodeCoverage YES
Important: App Store Submission
Never embed Quick in your production binary. Quick uses private APIs and will trigger automatic rejection.
Verify your build settings:
- Target Membership: Only check Quick and Nimble for your test targets
- Build Phases: Ensure frameworks are only in "Link Binary With Libraries" for test targets
- Archive Validation: Check that
Quick.frameworkandNimble.frameworkdo not appear in your archived product
Troubleshooting
"No such module 'Quick'"
- Solution: Ensure you're building the test target, not the main app target. Clean build folder (Cmd+Shift+K) and rebuild.
Swift Version Mismatch
- Error:
Module compiled with Swift X.X cannot be imported by Swift Y.Y - Solution: Update your
PodfileorPackage.swiftto use Quick/Nimble versions compatible with your Swift version (see Prerequisites table).
App Store Rejection: Private API Usage
- Error: ITMS-90338 or similar regarding non-public API usage
- Solution: Remove Quick from your app target. Go to Build Phases > Link Binary With Libraries for your main app target and remove Quick and Nimble. They should only exist in your test target.
Tests Not Appearing in Test Navigator
- Solution: Ensure your spec class inherits from
QuickSpec(orAsyncSpec) and overridesspec(). Check that the file is included in your test target's Compile Sources build phase.
Async/Sync DSL Confusion
- Error:
Cannot use async call in non-async closure - Solution: Use
AsyncSpecfor async tests andQuickSpecfor synchronous tests. Do not mix async calls inbeforeSuite/afterSuite—these intentionally remain synchronous to ensure proper test isolation.
CocoaPods Installation Issues
# If pods fail to install
pod deintegrate
pod cache clean --all
pod install
Slow Test Discovery
- Solution: Quick performs runtime test discovery. For large suites, ensure you're using the latest Quick version (v7.0.0+) which includes performance optimizations for example group creation.