新しいパッケージを作る
Swift 6系とターミナルを使います。入門で使ったフォルダーとは別に、新しい空のフォルダーを作ります。SwiftPMはSwiftに付属するビルド・依存関係管理ツールです。
mkdir StudyKit
cd StudyKit
swift package init --type library --name StudyKitPackage.swift、Sources、Testsが生成されます。次の例では生成された同名ファイルを全体ごと置き換えます。別のテストコードを残すと、同名の型や関数が重複することがあります。
Package.swiftで構成を確認
再現できる構成に揃えるため、Package.swiftを次の内容にします。最初の行は必要なツールのバージョンです。targetはビルドする単位、testTargetはテスト用の単位で、dependenciesに検査対象を書きます。
// swift-tools-version: 6.0
import PackageDescription
let package = Package(
name: "StudyKit",
products: [.library(name: "StudyKit", targets: ["StudyKit"])],
targets: [
.target(name: "StudyKit"),
.testTarget(name: "StudyKitTests", dependencies: ["StudyKit"])
]
)処理とテストを別ファイルへ
公開する関数にpublicを付けます。この例では個数が負の場合はエラーにするルールを定めます。
public enum TotalError: Error { case negativeCount }
public func total(price: Int, count: Int) throws -> Int {
guard count >= 0 else { throw TotalError.negativeCount }
return price * count
}Swift Testingの @Test はテストを登録し、#expect は期待する条件を検査します。throwsを持つテストではtryの失敗もテスト失敗として扱われます。
import Testing
@testable import StudyKit
@Test func normalTotal() throws {
#expect(try total(price: 120, count: 3) == 360)
}
@Test func zeroCount() throws {
#expect(try total(price: 120, count: 0) == 0)
}
@Test func negativeCount() {
#expect(throws: TotalError.self) {
try total(price: 120, count: -1)
}
}ビルドしてテストする
Package.swiftのあるフォルダーで実行します。ライブラリには画面やmainがないため、swift runではなくswift testで動作を確かめます。
swift build
swift testビルドが成功する
normalTotal、zeroCount、negativeCountの3テストが成功する試しに最初の期待値360を361へ変えるとnormalTotalが失敗します。360へ戻して再実行し、再び全件成功することを確認しましょう。テストを追加するときは通常の入力だけでなく、0や範囲外も検査します。
依存関係を管理する
この例は外部パッケージを使いません。追加が必要になったらPackage.swiftのdependenciesへパッケージを、targetのdependenciesへ利用する製品を指定します。下のコマンドは宣言済みの依存関係を解決し、状態を表示します。
swift package resolve
swift package show-dependenciesこの例では外部依存はない
依存を追加した場合は解決されたパッケージが表示される外部依存を使うアプリではPackage.resolvedも管理すると、使ったバージョンを共有できます。.buildは生成物なので通常Gitの管理対象にしません。ネットワークエラー時はURLと接続を確認します。
公式ドキュメントで確認する:Swift Package Managerの入門
練習:価格も検証する
価格が負の場合もTotalErrorを投げるように変更し、負の価格のテストを加えてください。以下は既存のソースとテストをそれぞれ置き換える解答例です。
解答例を確認する
public enum TotalError: Error { case negativeValue }
public func total(price: Int, count: Int) throws -> Int {
guard price >= 0, count >= 0 else { throw TotalError.negativeValue }
return price * count
}import Testing
@testable import StudyKit
@Test func normalTotal() throws {
#expect(try total(price: 120, count: 3) == 360)
}
@Test func zeroCount() throws {
#expect(try total(price: 120, count: 0) == 0)
}
@Test func negativeCount() {
#expect(throws: TotalError.self) { try total(price: 120, count: -1) }
}
@Test func negativePrice() {
#expect(throws: TotalError.self) { try total(price: -1, count: 3) }
}swift testで4テストが成功する