Running Swift unit tests from the CLI

August 16, 2018


Estimated reading time 4 minutes

Interview

Lately I’ve been playing around with serverside Swift and Swift via the CLI and unit testing. One of the problems I’ve run into is getting the SPM (Swift Package Manager) to run tests via the CLI.

Starting a new Swift project.

Via the CLI you can create a new project via the SPM with swift package init --type executable.

This creates a certain folder structure with a Sources and Tests folder. Open up Package.swift from your root project folder and make sure your Package.swift does contain the tool directive in comments (no idea what the official name of this is):
// swift-tools-version:4.0.

If you omit this directive it compiles via swift build. However when you add this directive, SPM returns different error messages. When I then run either swift build or swift test (like it says in your guide) the SPM(Swift Package Manager) returns with a warning: no targets to build in package to me. So we need to add this to the Package file.

Adding a testTarget.

Piecing everything together and adding the testTarget to the file, the complete Package.swift should look simething like this:

When running the tests now SPM gives me an error: "xcrun: error: unable to find utility "xctest", not a developer tool or in PATH". Running xctest can be done via xcrun xctest in the Terminal. This give a bunch of output and shows a path in the Arguments node.

Fixing it.

So following the the hint from the error I’ve added the "/Applications/Xcode.app/Contents/Developer/usr/bin/" to my path via export PATH="$PATH:/Applications/Xcode.app/Contents/Developer/usr/bin/". To confirm that it works check it with an echo $PATH.

Now when calling swift test I get to see the correct output, tests pass and it all works!

If that still does not work; After searching github and Stackoverflow I’ve found this which talks about Why isn’t swift build able to link XCTest?.

They say this:

The XCTest framework on Darwin isn’t a proper SDK framework, and is located at a different location within the Platform directory structure than frameworks like Foundation.

So we need to add the search paths to swift build like so:

When doing the same but for swift test I get to see the correct output, tests pass and it all works!

What I’ve also done (and later removed because swift test worked regardless of adding the search paths) is to create an alias which includes the search paths so you only have to type swift test and be done with it.

Hope this helps anyone who has run into the same problems. Or maybe add this to your docs if people have the same problem.

Make it pretty.

The output that swift test generates is fairly hard to read, but we can do something about that. xcpretty to the rescue! However when just piping the output to xcpretty does absolutely nothing. Weird… So searching through the Swift Forums I’ve found this:

This case with xcpretty is actually because swiftpm outputs test output to stderr, not stdout.

Ok let’s try again; Now we need to run swift test 2>&1 | xcpretty. Now we have a much more readable output. Me likes 🤓.

Conclusion

So you can run swift test from the commmandline we only need to make sure we are linking to the correct framework. And we can pipe xcpretty to stderr to make it’s output more readable.