Swiftpack.co - Package - q231950/the-stubborn-network

Travis SourceLevel

The Stubborn Network

A Swifty and clean stubbing machine.

The Stubborn Network makes your SwiftUI development more efficient and UI tests more reliable by stubbing responses of your network requests. It makes it easy to record new stubs and it speeds things up! You can find usage examples in The Stubborn Network Demo and below.

You can stub:

๐Ÿ‘ฎ๐Ÿปโ€โ™€๏ธ Unit Tests

Unit tests use "plain" stubs where each stub only lives for the duration of the test. This is called the ephemeral configuration.

Unit Test Example

/// given we create an ephemeral stubbed session (the scope of the stubs stays within this test)
let session = StubbornNetwork.makeEphemeralSession()

/// and stub individual requests
session.stub(NetworkClient.request, data: self.stubData, response: HTTPURLResponse(), error: nil)

let networkClient = NetworkClient(urlSession: session)

/// when

/// then
completion = networkClient.objectDidChange.sink { networkClient in
    XCTAssertEqual(networkClient.text, "417 bytes")

๐Ÿ•ต๐Ÿฝโ€โ™‚๏ธ UI Tests

UI tests benefit from The Stubborn Network's ability to easily record actual network requests and then play them back. This is done via the persistent configuration and a recording mode. In order to record and playback stubs you need to

  • configure your app to use a stubbed URLSession in its network layer when running tests
  • the tests on the other hand are required to inform The Stubborn Network which stub sources, in other words - which stubs to use for which test case

App Configuration

Instead of passing a standard URLSession to your network client a stubbed variant will be passed during UI test execution. This happens inside your application, for example a SceneDelegate.swift:

Example App Configuration

if processInfo.testing == true {
    /// The session is persistent, which means that stubs are stored
    let urlSession = StubbornNetwork.makePersistentSession()

    /// `.playback` is the default, so after recording you can remove the following line or set it to .playback
    urlSession.recordMode = .record

let networkClient = NetworkClient(urlSession: urlSession)

Test Configuration

There are 3 parameters passed in as environment variables to the application under test in order to specify that we want to stub network responses, what to stub, where to find/place them. Some of these will be handled more elegantly in the future:

  1. each test assigns its function name like testBytesText to create a dedicated stub source with stubs for network requests of each individual test case
  2. the stub path points to the directory where the stub source with the stubs is stored for .playback / where stubs will be recorded to when .record
  3. the TESTING parameter simply indicates to the application (see App Configuration above) that we are in a test environment
UI Test Configuration

override func setUp() {

    /// tell the app that we are executing tests right now
    app.launchEnvironment["TESTING"] = "TESTING"

    /// ... each stub's name will be the name of the test case
    app.launchEnvironment["STUB_NAME"] = self.name

    ///  .. and path to the stubs will be set to the project's directory
    let processInfo = ProcessInfo()
    app.launchEnvironment["STUB_PATH"] = "\(processInfo.environment["PROJECT_DIR"] ?? "")/stubs"

func testBytesText() {
    /// In the test itself everything happens like with an untempered URLSession
    let bytesText = app.staticTexts["417 bytes"]
    wait(forElement:bytesText, timeout:2)

๐Ÿ‘ฉ๐Ÿปโ€๐ŸŽจ SwiftUI Preview

A SwiftUI Preview utilizes The Stubborn Network mostly like a cache. You record and persist all network calls required to present a Preview and then have the responses available immediately for any successive Preview. This means you can record network calls and later show Previews without internet connection ๐Ÿ›ฉ

SwiftUI Example

static var previews: some View {
    let urlSession = StubbornNetwork.makePersistentSession(withName: "ContentView_Previews", path: "\(ProcessInfo().environment["PROJECT_DIR"] ?? "")/stubs")
    /// `.playback` is the default, so after recording you can remove the following line or set it to .playback
    urlSession.recordMode = .record

    let networkClient = NetworkClient(urlSession: urlSession)
    /// Use the stubbed `networkClient`...


Run Tests

You can run tests either from within Xcode (cmd+U) or from the command line: export STUB_DIR='./stubs' && swift test.


Stars: 3
Help us keep the lights on


Used By

Total: 1


0.0.6 - Nov 24, 2019

This release is giving a lot more control over the stubs' request and response body data. It is now possible to specify exactly what gets stored into a stub and what doesn't. For example credentials could be filtered out of the body data of a request before being stored as a stub. Another great feature is the ability to modify a response's data just before it gets delivered - if you ever had the need to adjust time stamps so that the stubs will be accepted by your app - now you can! As a hygiene factor this release gets rid of all linter warnings of the project ๐Ÿงผ

A new record mode allows to record only new requests and new stubs. This mode will improve the experience when adding new UITests a lot. No more stashing of the record mode after adding your new tests ๐Ÿ˜ƒ

Test coverage is up to 89.7% which should give a lot of confidence for working on the open issues.

0.0.5 - Oct 18, 2019

0.0.4 - Oct 12, 2019

0.0.3 - Oct 1, 2019

0.0.2 - Sep 8, 2019