Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing an executable with Swift

Tags:

xcode

swift

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
like image 776
Kilian Avatar asked Mar 13 '17 15:03

Kilian


People also ask

What is testing in 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.

How do I run a test case in IOS Swift?

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.


1 Answers

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: []
)
like image 166
Kilian Avatar answered Sep 21 '22 17:09

Kilian