June 23, 2020 · Swift Testing

Swift Package Testing

Swift 5.3 brings new improvements to the package manager so it finally supports including resources in your packages. You can read the proposal on Swift Evolution here if you're into that.

This has been the only reason I haven't moved libraries I maintain, such as MobiledocKit, to Swift Package Manager. In my tests, I often use example files to test that they are parsed correctly by the library and this was not easily done before. Now it is except there's one small caveat: the generated function Bundle.module will not work in tests. The function SPM generates looks about like this:

import class Foundation.Bundle

extension Foundation.Bundle {
    static var module: Bundle = {
        let bundlePath = Bundle.main.bundlePath + "/" + "MobiledocKit_MobiledocKitTests.bundle"
        guard let bundle = Bundle(path: bundlePath) else {
            fatalError("could not load resource bundle: \(bundlePath)")
        }
        return bundle
    }()
}

This does not work because the "main" bundle's path is nowhere near where SPM places the test bundle. If you try to use this in your tests, you'll get an error that starts like so:

swift package "Fatal error: could not load resource bundle:"

That's ok though, because we can fix the problem by making our own convenience method to find the right bundle:

extension Bundle {
    static let testBundle: Bundle = {
        let baseBundle = Bundle(for: <TEST CLASS NAME GOES HERE>.classForCoder())
        return Bundle(path: baseBundle.bundlePath + "/../<NAME OF THE GENERATE BUNDLE GOES HERE>.bundle")!
    }()
} 

If you use this method instead, your tests will be able to find the resources you listed in your Package.swift file and you can go about your day testing as you please.