Unit testing executable targets with Swift Package Manager

Hi there! I'm wondering if there is a way to unit test SwiftPM executable targets.

I believe this was allowed back in Swift 3/4, not sure at what point it changed. Was there a proposal for this change? Is this documented anywhere? And the million dollar question: is it possible to bring back this functionality?

This functionality has never existed. The advice has always been to have the tool consist only of this:

// main.swift
import LibraryImplementation
run()

That way everything is testable in library form.

Now that we have @main, it might be possible to compile with it disabled in order to build the executable itself as a library. But switching SwiftPMā€™s testing behaviour in this way would be a breaking change, so it might turn out to be contentious. Some packages test their executables from the outside by invoking them with Foundation.Process from the test module, and these would all break. (The strategy I mentioned before is superior over this one because it is compatible with test coverage tracking.)

Ok, so it was never implemented, that makes more sense.

I'm familiar with the executable/library approach. This in general works pretty well for command line tools, but it is a bit less convenient for AWS Lambda binaries, for example. I assume it's possible to move the lambda runtime code to a library, but doesn't feel right, if that makes sense.

I understand the challenge and complexity of allowing an executable module to be imported as a library for testing, but maybe this could be restricted to @testable import only?

Thanks!
Eneko

To be clear, I am not saying that no one is working on it. To my knowledge everyone agrees that it would be a good thing to have, and several recent proposals have been crafted with it intentionally in mind as a future direction. Iā€™m only saying itā€™s not as simple as flipping a switch and it could take time to get there.

Iā€™m pretty sure the team would welcome a proposalā€implementation pair, if you or some other reader wants to speed things along.

There is work ongoing in this area already: Allow tests to link against executable targets by abertelrud Ā· Pull Request #3103 Ā· apple/swift-package-manager Ā· GitHub

2 Likes

I've done this and it's easy enough. I have a main.swift that looks like

import App
import AWSLambdaRuntime

Lambda.run { context in
    return Handler(eventLoop: context.eventLoop)
}

Then in the App module I have the definition for the Handler