Swift 6.1 macOS 13+ MIT License

Stop writing mocks.
Start testing.

SwiftMock automatically generates mock implementations for your Swift protocols. Mark protocols with /// @mockable and let SwiftMock handle the boilerplate.

Terminal
$ swiftmock --source ./Sources --output ./Tests/Mocks/GeneratedMocks.swift
Found 12 mockable protocols
Generated mocks in 0.3s

Writing mocks is tedious

Every protocol needs a mock. Every method needs call tracking. Every parameter needs to be captured. It's repetitive, error-prone, and slows you down.

Time Consuming

Hours spent writing boilerplate mock code instead of actual tests

🔄

Repetitive Work

Same patterns repeated across every protocol in your codebase

⚠️

Error Prone

Manual mock updates often fall out of sync with protocol changes

Automatic mock generation

SwiftMock scans your Swift source files, finds protocols marked with /// @mockable, and generates complete mock implementations with call tracking, argument capture, and customizable handlers.

  • Zero manual mock maintenance
  • Always in sync with your protocols
  • Incremental builds for speed
  • Works with your existing workflow
Before
// Manually written mock
class UserServiceMock: UserService {
    var fetchCallCount = 0
    var fetchArgs: [String] = []
    var fetchHandler: ((String) -> User)?
    
    func fetch(id: String) -> User {
        fetchCallCount += 1
        fetchArgs.append(id)
        return fetchHandler!(id)
    }
    
    // ... repeat for every method
}
After
/// @mockable
protocol UserService {
    func fetch(id: String) -> User
}

// That's it! ✨

Everything you need for testing

SwiftMock generates production-ready mocks with all the features you need for comprehensive unit testing.

📊

Call Tracking

Every method gets a call counter. Verify exactly how many times your code called each method.

XCTAssertEqual(mock.fetchUserCallCount, 1)
📦

Argument Capture

All arguments are captured in arrays. Inspect exactly what values were passed to each call.

XCTAssertEqual(mock.fetchUserReceivedArguments.first, "123")
🎛

Custom Handlers

Define custom behavior for each method. Return different values, throw errors, or trigger side effects.

mock.fetchUserHandler = { id in User(id: id) }
⚡️

Async & Throws

Full support for async methods, throwing functions, and complex return types.

func deleteUser(id: String) async throws
🔄

Incremental Builds

Smart caching skips regeneration when source files haven't changed. Blazing fast CI builds.

swiftmock -s ./Sources -o ./Mocks.swift
📁

Flexible Output

Generate all mocks in one file or separate files per protocol. Organize however you prefer.

swiftmock --per-file -o ./Tests/Mocks/

Three steps to better testing

1

Mark your protocols

Add /// @mockable above any protocol you want to mock.

UserService.swift
/// @mockable
protocol UserService {
    func fetchUser(id: String) throws -> User
    func deleteUser(id: String) async throws
    func updateUserName(_ name: String, for id: String)
}
2

Run SwiftMock

Execute the command to scan your source files and generate mocks.

Terminal
$ swiftmock --source ./Sources --output ./Tests/Mocks/GeneratedMocks.swift
3

Write your tests

Use the generated mocks in your tests with full call tracking and custom handlers.

UserServiceTests.swift
func testUserFetch() {
    let mockService = UserServiceMock()
    
    // Set up mock behavior
    mockService.fetchUserHandler = { id in
        return User(id: id, name: "Test User")
    }
    
    // Execute test
    let user = try mockService.fetchUser(id: "123")
    
    // Verify
    XCTAssertEqual(mockService.fetchUserCallCount, 1)
    XCTAssertEqual(mockService.fetchUserReceivedArguments.first, "123")
    XCTAssertEqual(user.name, "Test User")
}

See what SwiftMock generates

SwiftMock produces clean, readable mock classes that follow Swift best practices. Each method gets call tracking, argument capture, and a customizable handler.

  • Public access for cross-module testing
  • Call count tracking per method
  • Full argument history capture
  • Customizable handlers with type safety
  • Fatal error if handler not set (catches test setup errors)
GeneratedMocks.swift
public final class UserServiceMock: UserService {
    public init() {}
    
    // MARK: - fetchUser
    var fetchUserCallCount = 0
    var fetchUserHandler: ((String) throws -> User)?
    var fetchUserReceivedArguments: [String] = []
    
    func fetchUser(id: String) throws -> User {
        fetchUserCallCount += 1
        fetchUserReceivedArguments.append(id)
        guard let handler = fetchUserHandler else {
            fatalError("fetchUserHandler must be set")
        }
        return try handler(id)
    }
}

Command-line options

SwiftMock provides flexible options to fit your project structure and workflow.

Flag Short Description
--source -s Required. Root directory to scan for Swift files
--output -o Required. Output file path for generated mocks
--exclude -e Comma-separated list of folders to exclude
--verbose -v Enable verbose output for debugging
--per-file Generate a separate mock file for each protocol
--force Force generation on every run (skip incremental check)

Automate with build phases

Add SwiftMock to your Xcode build phases to automatically regenerate mocks whenever your protocols change. Your mocks will always be in sync.

  1. Select your test target in Xcode
  2. Go to Build PhasesNew Run Script Phase
  3. Add the script shown on the right
  4. Build your project — mocks are regenerated automatically!
Build Phase Script
if which swiftmock >/dev/null; then
    swiftmock \
        -s "$SRCROOT/Sources" \
        -o "$SRCROOT/Tests/Mocks/GeneratedMocks.swift"
else
    echo "warning: SwiftMock not installed"
fi

Installation

📦

Swift Package Manager

Add SwiftMock to your Package.swift dependencies:

Package.swift
dependencies: [
    .package(
        url: "https://github.com/yourusername/SwiftMock.git",
        from: "1.0.0"
    )
]
🔧

Build from Source

Clone the repository and build the release binary:

Terminal
$ git clone https://github.com/yourusername/SwiftMock.git
$ cd SwiftMock
$ swift build -c release
$ cp .build/release/swiftmock /usr/local/bin/

Ready to simplify your testing?

Stop writing mock boilerplate. Start shipping features.