SwiftMock automatically generates mock implementations for your Swift protocols.
Mark protocols with /// @mockable and let SwiftMock handle the boilerplate.
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.
Hours spent writing boilerplate mock code instead of actual tests
Same patterns repeated across every protocol in your codebase
Manual mock updates often fall out of sync with protocol changes
SwiftMock scans your Swift source files, finds protocols marked with
/// @mockable, and generates complete mock implementations
with call tracking, argument capture, and customizable handlers.
// 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
}
/// @mockable
protocol UserService {
func fetch(id: String) -> User
}
// That's it! ✨
SwiftMock generates production-ready mocks with all the features you need for comprehensive unit testing.
Every method gets a call counter. Verify exactly how many times your code called each method.
XCTAssertEqual(mock.fetchUserCallCount, 1)
All arguments are captured in arrays. Inspect exactly what values were passed to each call.
XCTAssertEqual(mock.fetchUserReceivedArguments.first, "123")
Define custom behavior for each method. Return different values, throw errors, or trigger side effects.
mock.fetchUserHandler = { id in User(id: id) }
Full support for async methods, throwing functions, and complex return types.
func deleteUser(id: String) async throws
Smart caching skips regeneration when source files haven't changed. Blazing fast CI builds.
swiftmock -s ./Sources -o ./Mocks.swift
Generate all mocks in one file or separate files per protocol. Organize however you prefer.
swiftmock --per-file -o ./Tests/Mocks/
Add /// @mockable above any protocol you want to mock.
/// @mockable
protocol UserService {
func fetchUser(id: String) throws -> User
func deleteUser(id: String) async throws
func updateUserName(_ name: String, for id: String)
}
Execute the command to scan your source files and generate mocks.
$ swiftmock --source ./Sources --output ./Tests/Mocks/GeneratedMocks.swift
Use the generated mocks in your tests with full call tracking and custom handlers.
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")
}
SwiftMock produces clean, readable mock classes that follow Swift best practices. Each method gets call tracking, argument capture, and a customizable handler.
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)
}
}
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) |
Add SwiftMock to your Xcode build phases to automatically regenerate mocks whenever your protocols change. Your mocks will always be in sync.
if which swiftmock >/dev/null; then
swiftmock \
-s "$SRCROOT/Sources" \
-o "$SRCROOT/Tests/Mocks/GeneratedMocks.swift"
else
echo "warning: SwiftMock not installed"
fi
Add SwiftMock to your Package.swift dependencies:
dependencies: [
.package(
url: "https://github.com/yourusername/SwiftMock.git",
from: "1.0.0"
)
]
Clone the repository and build the release binary:
$ git clone https://github.com/yourusername/SwiftMock.git
$ cd SwiftMock
$ swift build -c release
$ cp .build/release/swiftmock /usr/local/bin/
Stop writing mock boilerplate. Start shipping features.