Swift Cheatsheet

Packages & Testing

Use this Swift reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Swift Package Manager commands

swift package init --type executable   # or --type library
swift build                            # debug build
swift build -c release                 # optimized build
swift run                              # build + run the executable
swift test                             # run all tests
swift test --filter ParserTests        # subset by suite/test name
swift test --parallel
swift package update                   # bump dependencies within constraints
swift package resolve                  # pin to Package.resolved

Layout convention: sources in Sources/<Target>/, tests in Tests/<Target>Tests/.

Package.swift

The manifest must start with the tools-version comment on line 1, or it will not build:

// swift-tools-version:6.0
import PackageDescription

let package = Package(
    name: "Practice",
    dependencies: [
        .package(url: "https://github.com/apple/swift-collections.git", from: "1.1.0"),
    ],
    targets: [
        .executableTarget(
            name: "Practice",
            dependencies: [
                .product(name: "Collections", package: "swift-collections"),
            ]
        ),
        .testTarget(name: "PracticeTests", dependencies: ["Practice"]),
    ]
)

The tools version also selects the language mode: 6.0 builds the package in Swift 6 mode (strict concurrency). Stay on Swift 5 semantics with the package-level swiftLanguageModes: [.v5] parameter (or a per-target .swiftLanguageMode(.v5) Swift setting) if needed.

Swift Testing (the default since Xcode 16)

import Testing
@testable import Practice

@Test func addsTwoNumbers() {
    #expect(add(2, 3) == 5)
}

@Test("parses negatives", arguments: ["-1", "-42"])
func parsesNegative(text: String) throws {
    let value = try #require(Int(text))   // unwrap or fail-and-stop
    #expect(value < 0)
}

@Suite("Parser")
struct ParserTests {
    @Test func emptyInputThrows() {
        #expect(throws: ParseError.empty) {
            try parse("")
        }
    }

    @Test(.disabled("tracked in #42"))
    func flakyPath() { }
}

#expect records a failure and keeps going, #require aborts the test. Failure output shows the values of each sub-expression, so one macro replaces the whole XCTAssert* family. Parameterized tests run once per argument. Async tests just add async and use await.

XCTest (legacy, still ubiquitous)

import XCTest
@testable import Practice

final class SolverTests: XCTestCase {
    override func setUp() {
        super.setUp()                       // runs before each test method
    }

    func testAdds() {
        XCTAssertEqual(add(2, 3), 5)
    }

    func testThrowsOnEmpty() {
        XCTAssertThrowsError(try parse("")) { error in
            XCTAssertEqual(error as? ParseError, .empty)
        }
    }

    func testFetch() async throws {
        let value = try await fetchScore(id: 1)
        XCTAssertGreaterThan(value, 0)
    }
}

XCTest and Swift Testing suites coexist in one swift test run, so codebases migrate incrementally. UI and performance tests (XCUIApplication, measure {}) remain XCTest-only.

Single-file practice

For online compilers and DSA judges, one main.swift with top-level code is the simplest shape:

swift main.swift                # run directly
swiftc -O main.swift -o sol && ./sol    # compile optimized, then run
swift --version

Move to a package when you need multiple files, dependencies, or a test suite.