ANTIGRAVITY LABEN
記事一覧/アプリ開発
アプリ開発/2026-05-04中級

Swift Testing × Antigravity — XCTest の限界を超えて AI 駆動テスト設計へ

Swift Testing フレームワークと Antigravity の組み合わせで iOS テスト品質を根本から変える実践ガイド。@Test・#expect マクロの活用から XCTest 移行戦略、Antigravity によるテスト自動生成まで体系的に解説します。

swift-testingios35xcode4testing15tddswift9antigravity435

プレミアム記事

「テストは全部グリーンなのに、App Store に申請したらクラッシュした」——この経験をした iOS 開発者は少なくないと思います。私自身、過去に同じ失敗を何度かやらかしており、その都度「テストって何のためにやってるんだろう」と悩みました。

原因を掘り下げてみると、多くのケースで共通の問題がありました。XCTest が持つ構造的な限界、具体的には「失敗したときに何が起きたか分かりにくい」「テストを書くコストが高いので後回しになる」「Async/Await との相性が悪くテストが不安定になる」といったことです。

Swift Testing は、この問題に正面から向き合うために Apple が設計したフレームワークです。Xcode 16 と Swift 5.10 から利用可能になり、マクロベースの宣言的な API で、今まで XCTest で感じていた「書きにくさ」を大幅に解消しています。

そして Antigravity との組み合わせが、このフレームワークをさらに強力にします。テスト対象のコードを Antigravity に渡して「Swift Testing 形式でテストを生成して」と依頼するだけで、適切な構造のテストコードが出てくる。もちろん生成されたコードをそのまま使うわけではありませんが、スタート地点として非常に優れています。

ここで扱うのはSwift Testing の設計思想から実践的な実装パターン、そして Antigravity を活かしたテスト生成ワークフローまで、体系的に解説します。

Swift Testing が XCTest と根本的に違う理由

まず、なぜ Apple が Swift Testing という新しいフレームワークを作ったのかを理解しておくことが大切です。

XCTest は 2013 年に登場し、Objective-C 時代の設計思想を引き継いでいます。クラスベースで、XCTAssert 系の関数を使い、失敗時のメッセージが限られています。Swift の進化(Concurrency、Generics、Macros)に追随するのが難しくなってきていました。

Swift Testing は、Swift 5.9 で導入された Macro システムを前提に設計されています。これにより、以下のことが実現できます。

失敗時の情報が圧倒的に豊富になる

XCTest の XCTAssertEqual(a, b) が失敗した場合、出力は「XCTAssertEqual failed: ("5") is not equal to ("6")」程度です。Swift Testing の #expect(a == b) は、ab の実際の値だけでなく、式の構造まで展開して表示します。複雑な条件式でも「どの部分が失敗したか」が一目でわかります。

テスト関数のオーバーヘッドがなくなる

XCTest では XCTestCase を継承したクラスが必須で、テスト関数名は test で始める必要がありました。Swift Testing では @Test アトリビュートを付けるだけで、どの関数でもテストになります。構造体(struct)でテストを書けるので、クラスの継承ヒエラルキーに縛られません。

パラメータ化テストがファーストクラス機能になった

XCTest でパラメータ化テストを実現しようとすると、ループを書くか外部ライブラリを使う必要がありました。Swift Testing では @Test(arguments:) で宣言的に書けます。

基本構文の実践 — @Test と #expect

実際のコードで確認しましょう。シンプルなカリキュレーター機能のテストを例にします。

import Testing
 
// テスト対象のコード
struct Calculator {
    func add(_ a: Int, _ b: Int) -> Int { a + b }
    func divide(_ a: Double, _ b: Double) throws -> Double {
        guard b != 0 else {
            throw CalculatorError.divisionByZero
        }
        return a / b
    }
}
 
enum CalculatorError: Error, Equatable {
    case divisionByZero
}
 
// Swift Testing でのテスト
@Suite("Calculator Tests")
struct CalculatorTests {
 
    let calculator = Calculator()
 
    @Test("加算が正しく計算される")
    func addition() {
        let result = calculator.add(3, 5)
        // #expect は失敗時に a=3, b=5, result=? を全て展開して表示する
        #expect(result == 8)
        #expect(result > 0)
    }
 
    @Test("ゼロ除算でエラーがスローされる")
    func divisionByZero() {
        // エラーがスローされることを検証する
        #expect(throws: CalculatorError.divisionByZero) {
            try calculator.divide(10, 0)
        }
    }
 
    @Test("正常な除算が成功する")
    func normalDivision() throws {
        // #require はテストを即中断する(アサーション失敗で続行しない)
        let result = try #require(try? calculator.divide(10, 2))
        #expect(result == 5.0)
        #expect(result.isFinite)
    }
}

期待する出力:

Test Suite 'Calculator Tests' started
✓ 加算が正しく計算される (0.001 seconds)
✓ ゼロ除算でエラーがスローされる (0.001 seconds)
✓ 正常な除算が成功する (0.001 seconds)
Test Suite 'Calculator Tests' passed (0.003 seconds)

#expect#require の違いを押さえておくことが大切です。#expect は失敗してもテストを続行しますが、#require は失敗した時点でテストを中断します。Optional の unwrap に #require を使うのが典型的なパターンで、XCTUnwrap の役割を担います。

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
XCTest で『テストは通るのに本番でバグが出る』問題に悩んでいた方が、Swift Testing の設計思想を理解して根本から解決できる
@Test・#expect・parameterized tests の実装パターンを習得し、Antigravity で高品質なテストを素早く自動生成できるようになる
既存 XCTest コードを壊さずに段階的に移行する具体的な戦略を身に付け、チームのリスクなくモダンなテスト環境へ移行できる
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

アプリ開発2026-04-05
AntigravityでiOSプライバシーマニフェストを自動生成・管理する実践ガイド
iOS 17以降で必須となったプライバシーマニフェスト(PrivacyInfo.xcprivacy)をAntigravityで自動生成・管理する方法を徹底解説。APIアクセス理由の記述からApp Store審査通過まで、実践的なワークフローを紹介します。
アプリ開発2026-07-04
App Intents で AppEnum が破綻する場面 — 毎日増える壁紙カタログを Siri に選ばせる EntityQuery 設計
App Intents のパラメータを AppEnum で書くと、選択肢が固定のうちは動きますが、毎日増えるコンテンツには耐えません。動的カタログを Siri とショートカットに正しく選ばせる AppEntity + EntityQuery 設計と、識別子の安定化・Spotlight 連携の落とし穴をまとめました。
アプリ開発2026-07-03
エージェントが書いた App Intent を Siri に喋らせる前に — 副作用で分類して確認ゲートを挟む設計
Antigravity が生成した App Intent を Siri やアシスタントに無確認で走らせると、破壊的な操作が音声一つで発火します。副作用で3分類し、確認ゲートを機械的に挟む実装と、欠落を push 前に弾く静的チェックをまとめました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →