Gauntlet is a collection of testing utility methods that aims to make writing great tests easier.

Overview

Gauntlet

What is Gauntlet?

Gauntlet is a collection of testing utility methods that aims to make writing great tests easier and with more helpful and descriptive failure states. It is only intended for inclusion in test cases. It has a dependency on XCTest but no external dependencies.

Requirements

  • XCode 13.2+
  • Swift 5.5+

Installation

The easiest way to install Gauntlet is by adding a dependency via SPM.

        .package(
            name: "Gauntlet",
            url: "https://github.com/krogerco/gauntlet-ios.git",
            .upToNextMajor(from: Version(1, 0, 0))
        )

… then reference in your test target.

        .testTarget(
            name: "MyTests",
            dependencies: ["MyFramework", "Gauntlet"],
            path: "MyFrameworkTests"
        )

How to Use Gauntlet

Gauntlet augments the standard XCTest unit testing methods to make unit tests more expressive and easier to read. Many of the methods in Gauntlet mirror those present in XCTest (e.g. XCTAsserEqual) but additionally include a closure that will be called if the assert passes.

For example, a typical unit test might look like:

func testSomething() throws {
    // Given
    let model = Model()

    // When
    model.doSomething()

    // Then
    XCTAssertNotNil(model.file)
    XCTAssertNotNil(model.file?.url)
    XCTAssertEqual(model.file?.url?.lastPathComponent, "myFile.json")
    XCTAssertFalse(model.file!.exists())
}

Unit tests involving optionals are commonly written like the above, either relying on force-unwraps or manual unwrapping of optionals to write all of the needed asserts. This leads to the following problems:

  • Force unwraps make the tests fragile. If the conditions are not met, the test will crash and no other tests will be run. You cannot know how many other tests would have passed or failed.
  • Manual unwrapping clutters up the code, and can lead to needing to write inline ternary statements to get the type needed for an assert.
  • You may need to disable swiftlint rules for your unit tests.
  • The expectation tree cannot be easily understood. if the first assert fails, there is no point in testing the following asserts.

A better version of this might look like the following:

func testSomething() throws {
    // Given
    let model = Model()

    // When
    model.doSomething()

    // Then
    XCTAssertNotNil(model.file)
    if let file = model.file {
        XCTAssertNotNil(file.url)

        if let url = file.url {
            XCTAssertEqual(url.lastPathComponent, "myFile.json")
        }

        XCTAssertFalse(file.exists())
    }
}

The fragility of the force unwraps has been eliminated, at the cost of readability of the code. Control flow is now intermingled with asserts.

Using Gauntlet and the addition of assert closures that are only executed on success, the meaning and expectations of the test become significantly more clear.

import Gauntlet
import XCTest

func testSomething() throws {
    // Given
    let model = Model()

    // When
    model.doSomething()

    // Then
    XCTAssertNotNil(model.file) { file in
        XCTAssertNotNil(file.url) { url in
            XCTAssertEqual(url.lastPathComponent, "myFile.json")
        }
        XCTAssertFalse(file.exists())
    }
}

When XCTAssertNotNil succeeds, the closure is called with the unwrapped value, ready to use in the next assert.

This leads to the following benefits:

  • You can tell at a glance what are the expectations of the test.
  • Optionals are safely unwrapped with minimal visual clutter.
  • Follow-on asserts are only executed when appropriate.
  • Code is compact and readable.

This functionality is made available to many of the assert methods you use today, and can be taken advantage of simply by adding a trailing closure.

For example, this code ensures you can test the contents of specific array indices without crashing if the array is underfilled.

XCTAssertEqual(myArray.count, 2) {
    XCTAssertEqual(myArray[0], "Hello")
    XCTAssertEqual(myArray[1], "World")
}

Other asserts also help remove boilerplate code when working with types like Result.

// Given, When
let result: Result<Any, Error> = ...

// Then
XCTAssertSuccess(result, is: String.self) { value in
    XCTAssertFalse(value.isEmpty)
}

In this case, XCTAssertSuccess eliminates the boilerplate code needed to convert the success type to the desired type and the switch statement that would subsequently needed for .success and .failure.

There are assert additions for a variety of cases, including: true, false, empty collections, equality, optionals, results, types, and more.

Note: Each function includes optional parameters for reporter, file, and line. These are hooks to test the functions themselves and in 99% of cases should be left to their default values for best results.

Why are they named like the XCTest provided methods?

We debated this very point quite a bit when writing Gauntlet. By sticking with the existing method prefixes we gain substantial benefits:

  • The discoverability of the enhanced methods is greatly increased. As you type the normal XCT prefix, auto-complete will list all possible variations that are available, including the new methods.
  • Readability at the call site is greatly increased. They look and read like the XCTest methods a developer is already familiar with.

In the unlikely event of a name collision in the future , the namespace of the module (either XCTest or Gaunlet) can be prepended at the callsite to disambiguate. If this were to happen, we would obviously strive to resolve this in a subsequent version of Gauntlet.

Extensions

Gauntlet also includes some extensions that can be useful when writing tests.

A static property currentQueueLabel has been added to DispatchQueue. This is useful when testing code that takes a queue that it calls a completion on to verify that the completion was called on the queue that was passed to that code.

Documentation

Gauntlet has full DocC documentation. After adding to your project, Build Documentation to add to your documentation viewer.

Communication

If you have issues or suggestions, please open an issue on GitHub.

You might also like...
Trying to implement Unit Tests for @Binding properties in a ViewModel

BindingTester Trying to implement Unit Tests for @Binding properties in a ViewModel ViewModel to be tested class SheetViewModel: ObservableObject {

Library for unifying the approach to network mocking in iOS unit- & UI-tests.

TinkoffMockStrapping Example To run the example project, clone the repo, and run pod install from the Example directory first. Requirements Installati

Catching fatal errors in unit tests

Precondition Catching When running tests which hit fatal errors, often preconditions the built-in support with XCTest. One package which supports cach

Small library to easily run your tests directly within a Playground
Small library to easily run your tests directly within a Playground

[] (https://developer.apple.com/swift/) Build Status Branch Status master develop About PlaygroundTDD enables you to use TDD directly on Xcode Playgro

Write unit tests which test the layout of a view in multiple configurations
Write unit tests which test the layout of a view in multiple configurations

Overview This library enables you to write unit tests which test the layout of a view in multiple configurations. It tests the view with different dat

UITest helper library for creating readable and maintainable tests

UITestHelper General information When creating UI tests you will see that you are often repeating the same pieces of code. The UITestHelper library wi

Upload failing iOS snapshot tests cases to S3
Upload failing iOS snapshot tests cases to S3

Second Curtain If you're using the cool FBSnapshotTestCase to test your iOS view logic, awesome! Even better if you have continuous integration, like

Tool for generating Acceptance Tests in Xcode, inspired by Fitnesse
Tool for generating Acceptance Tests in Xcode, inspired by Fitnesse

AcceptanceMark is a tool for generating Acceptance Tests in Xcode, inspired by Fitnesse. Read this blog post for a full introduction to AcceptanceMark

Snapshot view unit tests for iOS

iOSSnapshotTestCase (previously FBSnapshotTestCase) What it does A "snapshot test case" takes a configured UIView or CALayer and uses the necessary UI

Comments
  • Extend Concurrency API support

    Extend Concurrency API support

    What:

    CHANGES:

    • Add XCTAwaitAssertEqual.
    • Add XCTAwaitAssertNotNil.
    • Add XCTAwaitAssertFalse and XCTAwaitAssertTrue.

    DEPRECATED:

    • XCTAssertNoThrow in favor of XCTAwaitAssertNoThrow.
    • XCTAssertThrowsError in favor of XCTAwaitAssertThrowsError.

    Why:

    • To provide assertion functions for the Concurrency API.

    How:

    • Extending the support to @Sendable functions and adding consistent naming for the functions added.
    opened by EmilioOjeda 0
Releases(v1.1.0)
  • v1.1.0(Oct 28, 2022)

    What's Changed

    • Extend Concurrency API support by @EmilioOjeda in https://github.com/krogerco/Gauntlet-iOS/pull/2
    • Release 1.1.0 by @davidbarry-kr in https://github.com/krogerco/Gauntlet-iOS/pull/3

    New Contributors

    • @EmilioOjeda made their first contribution in https://github.com/krogerco/Gauntlet-iOS/pull/2
    • @davidbarry-kr made their first contribution in https://github.com/krogerco/Gauntlet-iOS/pull/3

    Full Changelog: https://github.com/krogerco/Gauntlet-iOS/compare/v1.0.0...v1.1.0

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Jun 28, 2022)

Owner
null
Swift framework containing a set of helpful XCTest extensions for writing UI automation tests

AutoMate • AppBuddy • Templates • ModelGenie AutoMate AutoMate is a Swift framework containing a set of helpful XCTest extensions for writing UI autom

PGS Software 274 Dec 30, 2022
Detailed explanations and implementations of various maths concepts for writing high performance code/algorithms backed with Unit tests.

Detailed explanations and implementations of various maths concepts which can help software Engineers write high performance code/algorithms backed with Unit tests.

Mussa Charles 2 Sep 25, 2022
Bluepill is a reliable iOS testing tool that runs UI tests using multiple simulators on a single machine

Bluepill is a tool to run iOS tests in parallel using multiple simulators. Motivation LinkedIn created Bluepill to run its large iOS test suite in a r

Mobile Native Foundation 3.1k Jan 3, 2023
SwiftCheck is a testing library that automatically generates random data for testing of program properties

SwiftCheck QuickCheck for Swift. For those already familiar with the Haskell library, check out the source. For everybody else, see the Tutorial Playg

TypeLift 1.4k Dec 21, 2022
Switchboard - easy and super light weight A/B testing for your mobile iPhone or android app. This mobile A/B testing framework allows you with minimal servers to run large amounts of mobile users.

Switchboard - easy A/B testing for your mobile app What it does Switchboard is a simple way to remote control your mobile application even after you'v

Keepsafe 287 Nov 19, 2022
Testing the UI without UI Testing, a Swift experiment.

UI tests without UI Testing experiment This repo is a small experiment to see if there's an "in-between" for testing iOS applications. More feature-le

Joe Masilotti 20 Sep 26, 2022
XCTestExtensions is a Swift extension that provides convenient assertions for writing Unit Test.

XCTestExtensions Features XCTAssertEventually (that convenient assertions for writing Unit Test). Use "XCTAssertEventually", you can write asynchronou

shindyu 22 Dec 1, 2022
Erik is an headless browser based on WebKit. An headless browser allow to run functional tests, to access and manipulate webpages using javascript.

Erik Erik is a headless browser based on WebKit and HTML parser Kanna. An headless browser allow to run functional tests, to access and manipulate web

Eric Marchand 544 Dec 30, 2022
Mockit is a Tasty mocking framework for unit tests in Swift 5.0

Mockit Introduction Mockit is a Tasty mocking framework for unit tests in Swift 5.0. It's at an early stage of development, but its current features a

Syed Sabir Salman-Al-Musawi 118 Oct 17, 2022
Swift Package with examples of how to tests iOS apps

GimmeTheCodeTDD A swift package with examples of unit tests in iOS development. Requirements Xcode 13 Content Dependency Injection Constructor Injecti

Dominik Hauser 8 Oct 11, 2021