Useful Swift Testing extensions for test targets.
Currently, the library provides a small but useful set of Swift Testing related extensions.
The #fail
condition is analogous to XCTest's XCTFail()
method and can be used as a stand-in for its functionality.
This can be useful when standard Swift Testing conditions are not possible:
enum Foo {
case bar(String)
}
@Test func fooTest() async throws {
let foo = Foo.bar("foo")
// test that variable `foo` is of the correct case,
// and unwrap its associated value
guard case let .bar(string) = foo else {
#fail
return
}
#expect(string == "foo")
}
It can be used with or without a comment.
#fail
#fail("Failure reason.")
A global TestResource
namespace and members are provided for accessing test resources in a test target.
Recommended structure for using TestResource
:
-
Create a base
TestResource
folder in your package's test target. -
Create subfolder(s) within the
TestResource
folder as desired in your package's testing target to contain the test resource files.For example, add the following to your
Package.swift
:.testTarget( // ... resources: [.copy("TestResource/TextFiles")] )
Note:
In some cases, naming any of these folders
"Resources"
may cause build errors. -
In the
TestResource
folder, create aTestResource.swift
file where you will declare test resource files available in the target.
For each file within any subfolder(s) located with the TestResource
folder, declare them individually as static properties.
For example, if a single subfolder named "TextFiles"
contains two files Foo.txt
and Bar.csv
then these would be declared as follows:
extension TestResource {
static let foo = TestResource.File(
name: "Foo", ext: "txt", subFolder: "TextFiles"
)
static let bar = TestResource.File(
name: "Bar", ext: "csv", subFolder: "TextFiles"
)
}
For complex testing environments it may be desirable to organize file declarations into sub-namespaces under the TestResource
extension. In that case, simply nest them under actors.
Note that each subfolder referenced would require an individual resources
declaration in your Package.swift
.
extension TestResource {
enum TextFiles {
static let subFolder = "TextFiles"
static let foo = TestResource.File(
name: "Foo", ext: "txt", subFolder: subFolder
)
// etc. ...
}
actor JSONFiles {
static let subFolder = "JSONFiles"
static let bar = TestResource.File(
name: "Bar", ext: "json", subFolder: subFolder
)
// etc. ...
}
}
To utilize these files in automated unit tests, access them as follows:
Getting a URL to a test resource file:
let url = try #require(try TestResource.foo.url())
Directly reading a test resource file's contents:
let data = try #require(try TestResource.foo.data())
TestResource
offers an optional feature to compress test resource files so that they occupy less storage space in the repository. For some file types this can result in dramatic space savings.
For each file within any subfolder(s) located with the TestResource
folder that are to be treated as compressed files, declare them individually as static CompressedFile
properties.
For example, if a single subfolder named "TextFiles"
contains two compressed files Foo.txt.lzfse
and Bar.csv.lzfse
then these would be declared as follows:
extension TestResource {
static let foo = TestResource.CompressedFile(
name: "Foo", ext: "txt", subFolder: "TextFiles", compression: .lzfse
)
static let bar = TestResource.CompressedFile(
name: "Bar", ext: "csv", subFolder: "TextFiles", compression: .lzfse
)
}
Each file that is declared as CompressedFile
must be compressed before adding to the repo.
These files can be compressed manually by running a temporary unit test case containing the following utility function:
@Test func temporaryFileCompressionUtility() throws {
// ie: an uncompressed file named "Foo.txt" is located on the desktop
let folder = URL.desktopDirectory
try TestResource.foo.manuallyCompressFile(locatedIn: folder)
// outputs "Foo.txt.lzfse" file to the desktop, ready to move into the package
}
The output file can then be moved into the package within the test target's /TestResource/X/
subfolder (where X
is an appropriate subfolder to contain the file).
Important
Ensure that this method is commented out or deleted after you are finished using it so that this operation is not called as part of your automated unit testing.
To utilize these files in automated unit tests, the uncompressed file contents may be read directly with a single method call:
// uncompresses the file's contents and returns it as Data
let data = try #require(try TestResource.foo.data())
At any time, a compressed resource file can be decompressed manually and written to an uncompressed file:
let folder = URL.desktopDirectory
try TestResource.foo.manuallyDecompress(intoFolder: folder)
// outputs "Foo.txt" file to the desktop
Important
Note that this method is not meant to be run as part of automated unit testing, but is provided as a utility when the file requires editing in order to be recompressed again and replaced in the package at a later time. For use in automated testing, call the data()
method instead to return the uncompressed raw file content.
- Add the package to your Xcode project's test target(s) using Swift Package Manager
- Select File → Swift Packages → Add Package Dependency
- Add package using
https://github.com/orchetect/swift-testing-extensions
as the URL.
- Import the module in your
*.swift
test files where needed.import Testing import TestingExtensions
-
In your
Package.swift
file:dependencies: [ .package(url: "https://github.com/orchetect/swift-testing-extensions", from: "0.2.0") ]
In each of your test target(s):
dependencies: [ .product(name: "TestingExtensions", package: "swift-testing-extensions") ]
-
Import the module in your
*.swift
test files where needed.import Testing import TestingExtensions
Most methods are implemented as category methods so they are generally discoverable.
All methods have inline help explaining their purpose and basic usage examples.
This package emits custom Swift macros.
Xcode includes a security mechanism that requires allowing 3rd-party macros before they are allowed to be used.
-
When running in the Xcode IDE, a dialog will pop up asking to allow the macros.
This will happen only once per commit of the repo where the macros originate. This means whenever the macros change or are updated, Xcode invalidates the previous authorization and re-prompts to allow them.
-
When running CI unit tests using
xcodebuild test
, if the process errors out, the simplest solution currently is to add the-skipMacroValidation
flag.
-
Additional methods may be added over time on an as-needed basis.
-
Currently only Apple platforms are supported. However, since Swift Testing is a multiplatform package, additional platforms may be supported in future, including Linux and/or Windows.
Coded by a bunch of 🐹 hamsters in a trenchcoat that calls itself @orchetect.
Licensed under the MIT license. See LICENSE for details.
This package has no affiliation with the Swift Testing project but is offered as-is for use in conjunction with it.
Bug fixes and improvements are welcome. Please open an issue to discuss prior to submitting PRs.