logo

XCTestParametrizedMacro

Swift Version License

概要

一个简单而强大的 Swift 宏,旨在简化单元测试的创建过程。 此工具允许您通过基于指定的参数自动生成测试方法,从而轻松地参数化您的 XCTest 方法。 只需编写一次测试方法,即可轻松生成具有不同参数的变体。 这种方法不仅简化了测试维护,还使识别失败的测试更加有效。 受 JUnit 参数化测试的启发。

要求

Xcode 15 或更高版本 Swift 5.9 或更高版本

安装

Xcode 项目

如果您正在使用 Xcode,请打开 File -> Add Package Dependencies... 并输入 URL https://github.com/pgssoft/XCTestParametrizedMacro

Swift Package Manager

Package.swift 中添加

dependencies: [
  .package(url: "https://github.com/pgssoft/XCTestParametrizedMacro", branch: "main")
]

然后将产品添加到您的测试目标。

.product(name: "XCTestParametrizedMacro", package: "XCTestParametrizedMacro"),

并在您的单元测试文件中导入它

import XCTestParametrizedMacro

示例

让我们考虑一个简单的例子。 您想为验证用户年龄的方法实现单元测试。

struct AgeValidator {
    static func isAdult(age: Int) -> Bool {
        age >= 18
    }
}

如果您想为几个值测试它,您可以编写两个泛型方法并使用宏为每个值创建一个单独的测试方法。

    @Parametrize(input: [18, 25, 99])
    func testAgeValidatorValidAge(input age: Int) throws {
        XCTAssertTrue(AgeValidator.isAdult(age: age))
    }

    @Parametrize(input: [2, 17])
    func testAgeValidatorInvalidAge(input age: Int) throws {
        XCTAssertFalse(AgeValidator.isAdult(age: age))
    }

宏将为每种情况生成一个测试方法。

    func testAgeValidatorValidAge_Age_18() throws {
        let age: Int = 18
        XCTAssertTrue(AgeValidator.isAdult(age: age))
    }

    func testAgeValidatorValidAge_Age_25() throws {
        let age: Int = 25
        XCTAssertTrue(AgeValidator.isAdult(age: age))
    }

    func testAgeValidatorValidAge_Age_99() throws {
        let age: Int = 99
        XCTAssertTrue(AgeValidator.isAdult(age: age))
    }

    func testAgeValidatorInvalidAge_Age_2() throws {
        let age: Int = 2
        XCTAssertFalse(AgeValidator.isAdult(age: age))
    }

    func testAgeValidatorInvalidAge_Age_17() throws {
        let age: Int = 17
        XCTAssertFalse(AgeValidator.isAdult(age: age))
    }

但是,作为输入参数,您也可以使用自定义类型。

    @Parametrize(input: [APIEndpoint.profile, APIEndpoint.transactions, APIEndpoint.order("2345")])
    func testEndpointURL(input endpoint: APIEndpoint) throws {
        XCTAssertNotNil(endpoint.buildURL)
    }

该宏将生成以下测试方法。

    func testEndpointURL_Endpoint_APIEndpoint_profile() throws {
        let endpoint: APIEndpoint = APIEndpoint.profile
        XCTAssertNotNil(endpoint.buildURL)
    }

    func testEndpointURL_Endpoint_APIEndpoint_transactions() throws {
        let endpoint: APIEndpoint = APIEndpoint.transactions
        XCTAssertNotNil(endpoint.buildURL)
    }

    func testEndpointURL_Endpoint_APIEndpoint_order_2345_() throws {
        let endpoint: APIEndpoint = APIEndpoint.order("2345")
        XCTAssertNotNil(endpoint.buildURL)
    }

您还可以指定预期值的数组并在测试中使用它。

    @Parametrize(
        input: [APIEndpoint.profile,
                APIEndpoint.transactions,
                APIEndpoint.order("2345")],
        output: ["https://example.com/api/me",
                 "https://example.com/api/transactions",
                 "https://example.com/api/order/2345"])
    func testEndpointURL(input endpoint: APIEndpoint, output expectedUrl: String) throws {
        XCTAssertEqual(endpoint.buildURL?.absoluteString, expectedUrl)
    }

因为例如上面的测试方法名称看起来很奇怪,您可以使用 labels 参数使用自定义命名。

    @Parametrize(
        input: [APIEndpoint.order("2345")],
        output: ["https://example.com/api/order/2345"]),
        labels: ["order"])
    func testEndpointURL(input endpoint: APIEndpoint, output expectedUrl: String) throws {
        XCTAssertEqual(endpoint.buildURL?.absoluteString, expectedUrl)
    }

宏将生成以下测试方法。

    func testEndpointURL_order() throws {
        let endpoint: APIEndpoint = APIEndpoint.order("2345")
        let expectedUrl: String =
                         "https://example.com/api/order/2345"
        XCTAssertEqual(endpoint.buildURL?.absoluteString, expectedUrl)
    }

特性

许可证

XCTestParametrizedMacro 在 MIT 许可下发布。 请参阅 LICENSE