← Back to Quick/Quick

How to Deploy & Use Quick/Quick

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 versionQuick versionNimble version
Swift 5.2+v3.0.0 or laterv9.0.0 or later
Swift 4.2 / Swift 5v1.3.2 or laterv7.3.2 or later
Swift 3 / Swift 4v1.0.0 or laterv5.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

  1. Open your .xcworkspace (if using CocoaPods) or .xcodeproj
  2. Select your test scheme (usually YourAppTests or YourAppUITests)
  3. 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.framework and Nimble.framework do 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 Podfile or Package.swift to 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 (or AsyncSpec) and overrides spec(). 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 AsyncSpec for async tests and QuickSpec for synchronous tests. Do not mix async calls in beforeSuite/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.