Skip to content

Convenient way to use collections of Sourcery stencils as an SPM plugins and Xcode plugins

License

Notifications You must be signed in to change notification settings

fenli/SourceryStencilPacks

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

24 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

SourceryStencilPacks

Convenient way to use collections of Sourcery stencils as an SPM plugins and Xcode plugins. This plugins provides simpler way to use sourcery binary with predefined templates without checking out whole sourcery repository. Learn more about it from the Sourcery here.

How to install

SPM

Add this configuration to your Package.swift:

dependencies: [
    .package(url: "https://github.com/fenli/SourceryStencilPacks", from: "0.3.0"),
],

Then add the plugins to your target:

.target(
    name: "MyPackage",
    plugins: [
        // Regular target plugins
        .plugin(name: "SourcePack", package: "SourceryStencilPacks")
    ]
)
.testTarget(
    name: "MyPackageTests",
    dependencies: ["MyPackage"],
    plugins: [
        // Test target plugins
        .plugin(name: "TestPack", package: "SourceryStencilPacks")
    ]
),

XCode

Integration into Xcode project:

  • In Xcode root project, navigate to your targets list in side bar.
  • Select target to integrate, eg: for TestPack plugins, select your *Tests target
  • Go to Build Phase -> Run Build Tool Plug-ins -> Add the plugin

Plugins

πŸš€ SourcePack

Utility for generating boilerplate code like hashable, equatable, copyable, etc. Here are all the supported annotations:

Annotation Description
Hashable Implements Hashable into classes, structs or enums
Equatable Implements Equatable into classes, structs or enums
Describable Implements CustomStringConvertible into classes, structs or enums
Copyable Implements copy function into classes or structs
DataRepresentable Combine all Hashable, Equatable, Describable, and Copyable

How to generate boilerplate functions

// Generate hash, equals(==) and copy functions
// sourcery: Hashable, Equatable, Copyable
struct Product {
    let name: String
    let price: Double
    let variants: [ProductVariant]
}

// Or simply use:
// sourcery: DataRepresentable
struct Product {
    let name: String
    let price: Double
    let variants: [ProductVariant]
}

πŸš€ TestPack

Utility for generating test doubles like mocks, stubs, and fakes (by generating random object).

How to generate mocks and fakes

Use Mockable annotation to protocols to generate mocks/stubs and Randomizable to structs or enums to generate random fakes

// Generate ProductServiceMock() class
// sourcery: Mockable
class ProductService {
    let repository: ProductRepository

    init(repository: ProductRepository) {
        self.repository = productRepository
    }
    
    func getProducts() async throws -> [Product] {
        return try await repository.getAllProducts()
    }
}

// Generate ProductRepositoryMock() class
// sourcery: Mockable
protocol ProductRepository {
    
    func getAllProducts() async throws -> [Product]
}

// Generate Product.random() static function
// sourcery: Randomizable
struct Product {
    let name: String // String.random() automatically generated
    let price: Double // Double.random() automatically generated
    let variants: [ProductVariant] // Need to annotate also on ProductVariant
}

// Generate ProductVariant.random() and [ProductVariant].random()
// sourcery: Randomizable=+array
struct ProductVariant: Equatable {
    let id: Int
    let name: String
}
import Testing
@testable import SamplePackage

struct ProductServiceTests {
    
    private var productRepositoryMock: ProductRepositoryMock!
    private var service: ProductService!
    
    init() {
        productRepositoryMock = ProductRepositoryMock()
        service = ProductService(productRepository: productRepositoryMock)
    }

    @Test
    func testGetAllProductsSuccess() async throws {
        // Generate fakes with random object
        let fakeProducts = (0...5).map {_ in Product.random() }

        // Use generated mocks for mocking/stubbing
        productRepositoryMock.getAllProductsProductReturnValue = fakeProducts

        // Action
        let result = try await service.getProducts()
        
        // Asserts
        #expect(result == fakeProducts)
    }
}

Note

For primitive and standard types, random extension automatically generated. For example like String.random(), Int.random(), Double.random(), etc.

If plugins is applied in .testTarget, the Mocks and Random object only available from unit test. But, if you prefer to apply on regular .target please use config debug_only=true so it's not included in release binary.

For more sample usage, please see the SamplePackage.

Optional: Custom configuration

Default plugin configuration should be suitable on most cases, but in case you need to customize it you can create .testpack.json inside your package directory (same level as Package.swift). All configuration keys here should be present otherwise it will use default value for all config.

{
    "debug_only": true,
    "random_std_lib": true,
    "random_std_lib_protection": "fileprivate",
    "imports": [],
    "testable_imports": []
}
Key Default Value Description
debug_only false Generate mocks/random for Debug build only. Default to false if applied on test target. If target is regular, then it's recommended to set as true
random_std_lib true Generate std lib random extension
random_std_lib_protection internal Protection level of std lib random extension. If target is regular, then it's recommended to set as fileprivate
imports [] List of additional imports to generated sources
testable_imports [] List of additional @testable imports to generated sources. Dependencies target is automatically added if target is test target.

Other testing libs integration

If you are using MockSwift, this plugin also provide autocreating the mocks using annotation // sourcery: MockSwift in your protocol. See sample here.

Are you using other testing tools to generate mock manually? you can suggest this plugin to integrate with that tools by submitting new issue.

License

SourceryStencilPacks is available under the Apache License Version 2.0. See LICENSE for more information.