Introducing @Mockable: A Swift Macro driven Testing Framework

Hello, Swift Community!

I’m excited to share with you a library that I've been working on called Mockable.

Mockable is a macro driven testing framework that provides automatic mock implementations for your protocols. It offers an intuitive declarative syntax that simplifies the process of mocking services in unit tests. The generated mock implementations can be excluded from release builds using compile conditions.

Example Usage

Given a protocol annotated with the @Mockable macro:

import Mockable

@Mockable
protocol ProductService {
    var url: URL? { get set }
    func fetch(for id: UUID) async throws -> Product
    func checkout(with product: Product) throws
}

A mock implementation named MockProductService will be generated, that can be used in unit tests like:

import MockableTest

lazy var productService = MockProductService()
lazy var cartService = CartServiceImpl(productService: productService)

func testCartService() async throws {
    let mockURL = URL(string: "apple.com")
    let mockError: ProductError = .notFound
    let mockProduct = Product(name: "iPhone 15 Pro")

    given(productService)
        .fetch(for: .any).willReturn(mockProduct)
        .checkout(with: .any).willThrow(mockError)

    try await cartService.checkout(with: mockProduct, using: mockURL)

    verify(productService)
        .fetch(for: .value(mockProduct.id)).called(.atLeastOnce)
        .checkout(with: .value(mockProduct)).called(.once)
        .url(newValue: .value(mockURL)).setCalled(.once)
}

The current feature set includes:

  • Support for properties, generic requirements and associated types
  • A custom Matcher for parameter checking to support non-equatable types
  • Relaxed Mode in which you can implicitly mock members without registration
  • Support for async verification with a custom timeout via calledEventually

Let me know if you have any ideas or questions regarding the package!

2 Likes