CocoaPods has test specs that provide the specifications for CocoaPods to create an Xcode target for building and running unit tests. How would you do something comparable in SwiftPM?
When you initialize a package from scratch, it includes a sample test:
mkdir Sample
cd Sample
swift package init
See the resulting Package.swift
and Tests
directory for the relevant code.
Run the all tests in one go like this:
swift test
(See swift test --help
for more fineâgrained options.)
If you want work with the packageâincluding testsâin Xcode, generate an Xcode project:
swift package generate-xcodeproj
open *.xcodeproj
(These instructions are for the current stable releases. Available Xcode Betas introduce new kinds of integration with SwiftPM from the Xcode side.)
Both of these approaches seem to run the tests on macOS only, even if I add platforms: [ .iOS(.v9) ],
to Package.swift
.
Is there a way to test on iOS targets using swift test
and/or swift package generate-xcodeproj
?
While SPM is now supported for dependency management for iOS, it still does not support defining or creating iOS projects.
Yes. See here:
Those instructions are for Xcode 10. I think Xcode 11 can infer more of the arguments on its own now, but I cannot remember which off the top of my head.
It has indirectly supported frameworks for iOS for a long time through generate-xcodeproj
. The iOSârelated portions of the generated Xcode project have been in working condition since at least Swift 4.0.
Two important things it cannot do are (a) directly crossâcompile without outside help such as Xcode and (b) specify resources, or by extension application bundles. But these are nothing specific to iOS.
Technically what it doesnât support yet is declaring a project to be limited to any specific platform. You cannot make an iOS project, because what you end up with is a crossâplatform macOSâLinuxâiOSâwatchOSâtvOSâAndroidâWindows project, though it may contain code that doesnât actually compile successfully for all of them.
That's a fair correction to my over simplification!
After checking back in with Xcode 12 and Swift Package Manager 5.3, it seems like there is still not Swift Package Manager support for running iOS unit tests. I'm only able to run my tests for macOS with swift test
.
Is there a way to run unit tests specified by a Package.swift on iOS like CocoaPods test specs?
If not, what is the recommended way to develop and run library unit tests when developing with Swift Package Manager?
You can use Xcode and xcodebuild
to interact with packages as well, so e.g. xcodebuild test
to run a package's unit tests. To target iOS, simply pass the appropriate -destination
to xcodebuild
.
Hello Boris,
Does it still require generating the Xcode project and then running xcodebuild? Hopefully we can move beyond that as it makes it a pain to generate and get code coverage of the right items as you lose control of the generated Xcode project unless you commit it to source control and make updating it manually a developer step.
Is that to say that there will not be a swift test iOS destination for the foreseeable future? Is it perceived as not needed? Why?
Sorry, you clarified that Xcode projects are not needed in another thread.
Here's what worked for me for a directory that contained a Package.swift
:
xcodebuild -list
xcodebuild -scheme {scheme-from-list} test -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 11'
It seems that the testTarget schemes only show up in xcodebuild -list
after manually being added in the Xcode UI from Manage Schemes
.
Is there a way to get testTargets to show up in xcodebuild -list
and be available for xcodebuild without an Xcode UI intervention?
Tests are associated with their products in the schemes, similar to how they are for regular Xcode targets. You should be able to get the same behaviour as swift test
by using the one scheme that's generated for packages with a single product or the one with -Package suffix if there are multiple products. Just pass that to xcodebuild test
and all tests should be running.
(Pre-context: I'm working with @paulb777 on the same thing )
Thanks for the info, I was able to get xcodebuild -scheme {Name}-Package ...
to run tests properly. That's a good fallback for our use case but we're going to have many products and many different test cases (Firebase), so testing the entire suite on a small change to one target/product will take a while and take a significant amount of machine time, so ideally we can get individual .testTarget
s running.
I'm not sure what you mean by:
I understand the regular Xcode bit, but wasn't sure how to associate a .testTarget
with an associated .target
or .product
. I looked through the API but didn't find a way to specify... is there a naming scheme to follow in order to get them to associate with one another? I tried <TargetName>Tests
and xcodebuild -scheme <TargetName> test ...
but that didn't work for me.
Thanks!
(Full context, we're working on getting SwiftPM Firebase tests working on GitHub Actions: SPM: Core ObjC unit tests by paulb777 ¡ Pull Request #5959 ¡ firebase/firebase-ios-sdk ¡ GitHub)
IIRC, the test target's dependencies are used to do the association. So I think if <TargetName>Test
depends on <TargetName>
, the corresponding scheme should run those tests. Let me know if that doesn't work and I'll take a look at the implementation to refresh my memory on how it actually works :)
That doesn't seem to be the case for https://github.com/firebase/firebase-ios-sdk/blob/master/Package.swift. The tests are only available with the package scheme.
I tried renaming the test targets to FirebaseCoreTest
and FirebaseStorageTest
, but that didn't make a difference
Looks like the way it actually works is this:
- the *-Package scheme gets all test targets of the package associated with it
- for executable targets, we follow this API: swift-package-manager/PackageGraph.swift at 16c2d075cbce8fdb59e4332e9be1e54e931f5077 ¡ apple/swift-package-manager ¡ GitHub
- for library products, we don't associate any tests
So one suggestion to get the behaviour you want with current Xcode would be to add a dummy executable target that gets the right tests based on the SwiftPM logic. Please also file a radar with the behaviour you would like to see.
I found that I can create the Unit Test schemes in the Xcode UI, commit the generated shared schemes, and then the unit tests are available to select for CI testing.
I successfully managed to successfully run Swift package unit tests (no xcodeproj file) on an iOS simulator with the following command:
xcodebuild -scheme <scheme> test -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 11'
Find your scheme name by executing:
xcodebuild -list