SwiftFixture

0.2.0

A tool to help you in writing clean and concise unit tests by standardizing the creation of fixture values.
liamnichols/swift-fixture

What's New

0.2.0

2023-07-02T22:39:41Z

What's Changed

Full Changelog: 0.1.0...0.2.0

SwiftFixture

Test Status

A simple framework for managing test fixtures in Swift.

Overview

SwiftFixture provides a set of tools designed to help make it easy for you to instantiate and organize values of your own Swift types for use as fixtures during unit testing.

@ProvideFixture
struct User {
    let id: UUID
    let name: String
    let createdAt: Date
    let isActive: Bool
}

func getSummary(for user: User) -> String {
    if user.isActive {
        return "\(user.name) is currently active!"
    } else {
        return "\(user.name) is not active."
    }
}
class UserTests: XCTestCase {
    let fixture = Fixture()
    
    func testSummaryForActiveUser() throws {
        let user: User = try fixture(isActive: true)
        
        XCTAssertEqual(getSummary(for: user), "\(user.name) is active!")
    }
}

Why?

Every unit test needs a fixture. Put simply, a fixture is just a piece of information that controls the environment of the test. When testing Swift code, types are your fixtures, like user in the above example.

With every unit test written, you will find yourself needing to initialize values more and more. This can start to become repetitive and as your types grow in complexity, it's likely that the initializer argument list also grows. It's not uncommon to eventually find yourself writing something like this:

func testStateForSubscribedUser() {
    let user = User(
        id: UUID(),
        name: "ksdf",
        itemCount: 0,
        createdAt: Date(),
        subscription: Subscription(
            id: UUID(),
            startedAt: Date(),
            expires: Date(),
            paymentMethod: .iap,
            referralCode: nil
        ),
        profileState: .complete,
        avatar: nil
    )
    
    XCTAssertEqual(user.state, .subscribed)
}

func testStateForUserWithoutSubscription() {
    let user = User(
        id: UUID(),
        name: "ksdf",
        itemCount: 0,
        createdAt: Date(),
        subscription: nil,
        profileState: .complete,
        avatar: nil
    )
    
    XCTAssertEqual(user.state, .unsubscribed)
}

func testStateForUserWithExpiredSubscription() {
    let user = User(
        id: UUID(),
        name: "ksdf",
        itemCount: 0,
        createdAt: Date(),
        subscription: Subscription(
            id: UUID(),
            startedAt: Date(timeIntervalSinceReferenceDate: 0),
            expires: Date(timeIntervalSinceNow: -10),
            paymentMethod: .iap,
            referralCode: nil
        ),
        profileState: .complete,
        avatar: nil
    )
    
    XCTAssertEqual(user.state, .expired)
}

The three simple tests above end up using 90% more lines of code than they really needed and overall things end up pretty noisy. Additionally, making unrelated changes to User such as adding a new property require that we go back and add a new default value to each test when that property shouldn't even have been associated with this test in the first place.

With a few helper methods, you can certainly improve this a bit, but it can be hard to do so consistently when you end up having to write your own helpers. Furthermore, it is also very tempting to do things that influence your production code, such as providing default values on the main initializer.

SwiftFixture is designed to worry about all of this so that you don't have to.

How?

Check out the the documentation for guidance using SwiftFixture.

Inspiration

This library was inspired by KFixture, a Kotlin wrapper around JFixture (inspired by AutoFixture).

Description

  • Swift Tools 5.9.0
View More Packages from this Author

Dependencies

  • SwiftSyntax509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-06-05-a
Last updated: Thu Mar 14 2024 10:58:34 GMT-0900 (Hawaii-Aleutian Daylight Time)