PGSSoft / XCTestParametrizedMacro

Swift macro for parametrizing unit test methods
MIT License
123 stars 7 forks source link

How is this different from a `for` loop? #17

Closed davdroman closed 9 months ago

davdroman commented 9 months ago

Not trying to bash this effort, I'm just curious about this library's angle.

How is this:

@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))
}

... different from:

func testAgeValidator() {
    let validInputs = [18, 25, 99]
    for input in validInputs {
        XCTAssertTrue(AgeValidator.isAdult(age: age))
    }

    let invalidInputs = [2, 17]
    for input in invalidInputs {
        XCTAssertFalse(AgeValidator.isAdult(age: age))
    }
}

... besides the splitting into individual test functions?

Is there an aspect of unit testing that's hard to do with for loops but this library makes substantially easier via @Parametrize?

mkowalski87 commented 9 months ago

@davdroman Thanks for sharing your opinion.

Our main intention is readability and this approach is more in line with data-driven testing methodology (https://en.wikipedia.org/wiki/Data-driven_testing).

So with a different test method for each input argument is better because, in case of failure, it is easier to discover the failing scenario, assuming you have meaningful names.

Maybe for such a simple case as in readme, it doesn't make sense to use it. But we believe can be useful for more complex scenarios.

    @Parametrize(input: ["001",
                         "002",
                         "003"],
                 output: [("Saving Account", NSDecimalNumber(string: "3000")),
                          ("Kredit Account", NSDecimalNumber(string: "-15000")),
                          ("Basic Account", NSDecimalNumber(string: "2345"))],
                 labels: ["SavingAccount",
                          "KreditAccount",
                          "BasicAccount"])
    func testAccountViewModel(input accountId: String,
                              output expected: (String, NSDecimalNumber)) throws {
        let viewModel = AccountViewModel(accountService: accountServiceMock,
                                         accountId: accountId)
        XCTAssertTrue(viewModel.isLoading)
        let expectation = expectation(description: "refresh call")
        viewModel.refresh {
            expectation.fulfill()
        }
        wait(for: [expectation])
        XCTAssertFalse(viewModel.isLoading)
        XCTAssertEqual(viewModel.accountName, expected.0)
        XCTAssertEqual(viewModel.balance, expected.1)
    }

But we are open to any suggestions to make this macro more helpful.

davdroman commented 9 months ago

Oh yeah I can see how that simplifies things. Thanks for illustrating! 👍