---
title: XCTestからSwift Testingへ
tags:  #ios #関モバ  
author: [USAMI Kosuke](https://www.docswell.com/user/usami-k)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/PJRWDK5479.jpg?width=480
description: 関西モバイルアプリ研究会A #5 - connpass https://kanmoba.connpass.com/event/329447/  #関モバ でSwift Testingの話をしました - usami-kの日記 https://usami-k.hatenablog.com/entry/2024/09/26/000522
published: September 25, 24
canonical: https://www.docswell.com/s/usami-k/5222XR-swift-testing
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/PJRWDK5479.jpg)

XCTest から Swift Testing へ
宇佐見公輔
2024-09-25
株式会社ゆめみ


# Page. 2

![Page Image](https://bcdn.docswell.com/page/PEXP1LKZ7X.jpg)

自己紹介
• 宇佐見公輔
• 株式会社ゆめみ
‣ iOS テックリード
• iOSDC Japan 2024
‣ パンフレット記事 / ポスターセッション
1 / 24


# Page. 3

![Page Image](https://bcdn.docswell.com/page/3EKD2L5VJD.jpg)

Swift Testing とは


# Page. 4

![Page Image](https://bcdn.docswell.com/page/L73R431QJ5.jpg)

Swift Testing とは
• Swift 用の単体テストフレームワーク
‣ 従来の XCTest に比べて、Swift の機能をより活用
• Swift 公式の GitHub リポジトリで公開されている
‣ https://github.com/swiftlang/swift-testing
• Xcode 16 に統合された
‣ Xcode の UI と連携する
Swift Testing とは
3 / 24


# Page. 5

![Page Image](https://bcdn.docswell.com/page/87DYQ4XW7G.jpg)

XCTest と Swift Testing
• XCTest
‣ 従来からの単体テストフレームワーク
• Objective-C 時代から存在、Swift にも適合
‣ https://github.com/swiftlang/swift-corelibsxctest
• XCTest と Swift Testing は同じプロジェクトで混在可能
‣ そのため、少しずつ移行していくことが可能
Swift Testing とは
4 / 24


# Page. 6

![Page Image](https://bcdn.docswell.com/page/VJP6LMPXE8.jpg)

Swift Testing の基本


# Page. 7

![Page Image](https://bcdn.docswell.com/page/2EV3Q9237Q.jpg)

テスト関数定義：XCTest
import XCTest
class FoodTruckTests: XCTestCase {
func testEngineWorks() {
// ...
}
}
• XCTestCase のサブクラス内で定義する必要
• メソッド名を test 始まりで命名する必要
Swift Testing の基本
6 / 24


# Page. 8

![Page Image](https://bcdn.docswell.com/page/57G3WZRYJL.jpg)

テスト関数定義：Swift Testing
import Testing
struct FoodTruckTests {
@Test
func engineWorks() {
// ...
}
}
• テスト関数はどこで定義してもよい
• @Test 属性をつければメソッド名は自由
Swift Testing の基本
7 / 24


# Page. 9

![Page Image](https://bcdn.docswell.com/page/4EQ53LV6JP.jpg)

テストの実装
// XCTest
func testEngineWorks() throws {
XCTAssertNotNil(engine.parts.first)
XCTAssertGreaterThan(engine.batteryLevel, 0)
XCTAssertTrue(engine.isRunning)
}
// Swift Testing
@Test func engineWorks() throws {
try #require(engine.parts.first != nil)
#expect(engine.batteryLevel &gt; 0)
#expect(engine.isRunning)
}
Swift Testing の基本
8 / 24


# Page. 10

![Page Image](https://bcdn.docswell.com/page/KJ491DMM71.jpg)

Optional 値の Unwrap
// XCTest
func testEngineWorks() throws {
let part = try XCTUnwrap(engine.parts.first)
}
// Swift Testing
@Test func engineWorks() throws {
let part = try #require(engine.parts.first)
}
Swift Testing の基本
9 / 24


# Page. 11

![Page Image](https://bcdn.docswell.com/page/LE1KGZ8YJG.jpg)

テスト実行時の setup/teardown
// XCTest
class FoodTruckTests: XCTestCase {
override func setUp() async throws {
// ...
}
}
// Swift Testing
final class FoodTruckTests {
init() async throws {
// ...
}
}
Swift Testing の基本
10 / 24


# Page. 12

![Page Image](https://bcdn.docswell.com/page/GEWDK9Z1J2.jpg)

変換ツール
• XCTest のコードを Swift Testing に変換するツール
‣ https://github.com/giginet/swift-testingrevolutionary
Swift Testing の基本
11 / 24


# Page. 13

![Page Image](https://bcdn.docswell.com/page/47ZGZ91XE3.jpg)

Swift Testing の機能


# Page. 14

![Page Image](https://bcdn.docswell.com/page/YJ6YZKLP7V.jpg)

パラメータを変えてテスト
enum Food {
case burger, iceCream, burrito, noodleBowl, kebab
}
@Test(arguments: [
Food.burger, .iceCream, .burrito, .noodleBowl, .kebab
])
func foodAvailable(_ food: Food) async throws {
let foodTruck = FoodTruck(selling: food)
#expect(await foodTruck.cook(food))
}
Swift Testing の機能
13 / 24


# Page. 15

![Page Image](https://bcdn.docswell.com/page/GJ5GWP1PJ4.jpg)

複数のパラメータ
@Test(arguments: zip(Food.allCases, 1 ... 100))
func makeLargeOrder(of food: Food, count: Int) async
throws {
let foodTruck = FoodTruck(selling: food)
#expect(await foodTruck.cook(food, quantity: count))
}
Swift Testing の機能
14 / 24


# Page. 16

![Page Image](https://bcdn.docswell.com/page/LE3R431675.jpg)

テスト実行制御
@Test(.enabled(if: FoodTruck.sells(.arepas)))
func arepasAreTasty() {
// ...
}
@Test(.timeLimit(.seconds(30))
func serveLargeOrder() {
// ...
}
Swift Testing の機能
15 / 24


# Page. 17

![Page Image](https://bcdn.docswell.com/page/8EDYQ4XMEG.jpg)

アノテーション
@Test func grillWorks() async {
withKnownIssue(&quot;Grill is out of fuel&quot;) {
try FoodTruck.shared.grill.start()
}
}
Swift Testing の機能
16 / 24


# Page. 18

![Page Image](https://bcdn.docswell.com/page/V7P6LMPQJ8.jpg)

非同期処理のテスト


# Page. 19

![Page Image](https://bcdn.docswell.com/page/2JV3Q92PEQ.jpg)

非同期処理のテスト：XCTest
func testTruckEvents() async {
let soldFood = expectation(description: &quot;…&quot;)
FoodTruck.shared.eventHandler = { event in
soldFood.fulfill()
}
await Customer().buy(.soup)
await fulfillment(of: [soldFood])
}
expectation
非同期処理のテスト
を使う。fulfill() が呼ばれたら成功。
18 / 24


# Page. 20

![Page Image](https://bcdn.docswell.com/page/5EG3WZRQ7L.jpg)

非同期処理のテスト：Swift Testing
@Test func truckEvents() async {
await confirmation(&quot;…&quot;) { soldFood in
FoodTruck.shared.eventHandler = { event in
soldFood()
}
await Customer().buy(.soup)
}
}
confirmation
非同期処理のテスト
を使う。confirmed が呼ばれたら成功。
19 / 24


# Page. 21

![Page Image](https://bcdn.docswell.com/page/4JQ53LVW7P.jpg)

注意点
• XCTest の expectation では await fulfillment() で完了
待ちをしていた。
• Swift Testing の confirmation は完了待ちをしない。ブ
ロックを抜けるまでに confirmed メソッドが呼ばれない
と失敗扱い。
この点では、不便になっているようにも見えるが・・・
非同期処理のテスト
20 / 24


# Page. 22

![Page Image](https://bcdn.docswell.com/page/K7491DM1E1.jpg)

解決策(1)
Swift Concurrency の withCheckedContinuation を使う。
@Test func truckEvents() async {
await confirmation(&quot;…&quot;) { soldFood in
await withCheckedContinuation { continuation in
FoodTruck.shared.eventHandler = { event in
soldFood()
continuation.resume()
}
await Customer().buy(.soup)
}
}
}
非同期処理のテスト
21 / 24


# Page. 23

![Page Image](https://bcdn.docswell.com/page/LJ1KGZ857G.jpg)

解決策(2)
pointfreeco/swift-concurrency-extras の megaYield
を使う。
@Test func truckEvents() async {
await confirmation(&quot;…&quot;) { soldFood in
FoodTruck.shared.eventHandler = { event in
soldFood()
}
await Customer().buy(.soup)
await Task.megaYield()
}
}
非同期処理のテスト
22 / 24


# Page. 24

![Page Image](https://bcdn.docswell.com/page/GJWDK9ZW72.jpg)

まとめ


# Page. 25

![Page Image](https://bcdn.docswell.com/page/4EZGZ912J3.jpg)

XCTest から Swift Testing へ
• XCTest から段階的に移行できる
• 機械的に移行できる部分も多い
• パラメータテストが便利
• 非同期処理のテストは少し変わっているので注意
まとめ
24 / 24


