I created an executable with Swift via swift package init --type executable
and would now like to write a few tests for it. This doesn't appear to be an issue at all for library packages, in that case Swift also populates the Tests
directory with a tests module which runs nicely via swift test
. For an executable only an empty Tests
directory is created.
On trying to run tests for my executable from within Xcode or via swift test
I'm running into linker issues though that seem to specify that Swift is unable to link the contents of my main.swift to the tests. I'm not sure what I can do here. I've tried playing around within Xcode to create new framework targets to be linked, but none of that would be picked up by swift test
anyways as far as I can tell. I didn't manage to get it working via Xcode either. The following is the output from swift test
.
Compile Swift Module 'swifttest' (1 sources)
Linking ./.build/debug/swifttest
Compile Swift Module 'swifttestTests' (1 sources)
Linking ./.build/debug/swifttestPackageTests.xctest/Contents/MacOS/swifttestPackageTests
Undefined symbols for architecture x86_64:
"__TF9swifttest3fooFT_SS", referenced from:
__TFFC14swifttestTests14SwifttestTests7testFooFT_T_u0_KzT_SS in swifttestTests.swift.o
ld: symbol(s) not found for architecture x86_64
<unknown>:0: error: link command failed with exit code 1 (use -v to see invocation)
<unknown>:0: error: build had 1 command failures
error: exit(1): /Applications/Xcode-beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-build-tool -f /Users/kilian/Desktop/swifttest/.build/debug.yaml test
These are the contents of my files for reference. It's a minimal example project.
main.swift
public func foo() -> String {
return "bar"
}
print(foo())
swifttestTests.swift
import Foundation
import XCTest
import swifttest
class SwifttestTests: XCTestCase {
func testFoo() {
XCTAssertEqual("bar", foo())
}
}
Directory Layout
.
├── Package.swift
├── Sources
│ └── main.swift
└── Tests
└── swifttestTests
└── swifttestTests.swift
It is a process of creating small functionality-based tests for a particular unit of code, which will eventually ensure that all other units will pass the test. The Test navigator provides the easiest way to work with tests; you'll use it to create test targets and run tests against your app.
Writing Unit Test Cases in Swift With an ExampleUnit test cases run with the testing target. Always check if you have a unit test target or not, if not, then add it. Then under this target, you need to create a new test case file. You will use this new file for writing test cases.
Whilst not exactly a solution to not being able to test an executable I was made aware of a workaround. The basic idea is to move more or less everything into a second module inside the same project and minimizing the executable target to a call to an entry function.
A basic structure following the given example would look like this:
.
├── Package.swift
├── Sources
│ └── swifttest
│ │ └── main.swift
│ └── SwiftTestLib
│ └── foo.swift
└── Tests
└── SwiftTestLibTests
└── SwiftTestLibTests.swift
This makes it necessary however to specify the targets in the Package.swift
.
import PackageDescription
let package = Package(
name: "swifttest",
targets: [
Target(name: "swifttest", dependencies: ["SwiftTestLib"]),
Target(name: "SwiftTestLib", dependencies: []),
],
dependencies: []
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With