Swift Digest
ST-0010 | Swift Evolution

ConditionTrait を評価するためのパブリック API

Public API to evaluate ConditionTrait

Proposal
ST-0010
Authors
David Catmull
Review Manager
Stuart Montgomery
Status
Implemented (Swift 6.2)

このダイジェストはClaude Opus 4.7 / 4.8によって生成されたものです(License)。原文はこちら

01 何が問題だったのか

Swift Testing には、.enabled(if:).disabled(if:) といった、条件によってテストの実行可否を切り替えるための trait があります。これらは内部的に ConditionTrait という型で表現されていて、テスト本体を実行する前に条件を評価し、結果に応じてテストをスキップするかどうかを決めています。

ところが、この条件を評価する経路はこれまで ConditionTrait.prepare(for:) メソッドの内側にしか存在せず、しかも prepare(for:) は引数として Test のインスタンスを必要としていました。Test は本来テスティングライブラリがテスト関数を発見・実行する過程で組み立てるもので、外部から手で作ることを想定した型ではありません。

そのため、サードパーティ製のライブラリが「自前のテスト分割やセクションごとに ConditionTrait を適用したい」と思っても、ダミーの Test を用意して prepare(for:) に渡す以外に評価する手段がなく、事実上 ConditionTrait を再利用できない状態になっていました。

02 どのように解決されるのか

ConditionTrait に、条件を評価して結果を返すだけの公開メソッド evaluate() を追加します。Test のインスタンスを渡す必要はなく、ConditionTrait 単体で評価できます。

extension ConditionTrait {
    /// Evaluate this instance's underlying condition.
    ///
    /// - Returns: The result of evaluating this instance's underlying condition.
    ///
    /// The evaluation is performed each time this function is called, and is not
    /// cached.
    public func evaluate() async throws -> Bool
}

返り値は条件の評価結果である Bool で、たとえば .enabled(if: someCondition) のような trait に対して evaluate() を呼ぶと、someCondition を実際に評価して得られた値が返ってきます。評価は呼び出すたびに行われ、結果はキャッシュされません。条件式自体がエラーを throw する形で書かれている場合は、evaluate() もそのエラーを throw します。

既存の prepare(for:) メソッドはこの evaluate() を内部で呼び出すように書き換えられるため、評価ロジック自体は二重に持たれることなく、prepare(for:) の挙動はこれまでと変わりません。

これにより、サードパーティ製のライブラリは、テストをより細かいセクションに区切って実行するような独自の仕組みの中でも、Swift Testing 標準の ConditionTrait をそのまま流用できるようになります。たとえばスイートやテスト関数といった単位ではなく、テスト内のサブセクションに対して .enabled(if:) を適用するような使い方が可能になります。

03 今後の見通し

今回の変更は ConditionTrait についてのみ評価用 API を公開するもので、他の trait をサードパーティから同様に扱えるようにするかどうかは別の Proposal で扱われる見込みです。これは将来の構想であり、実現を約束するものではありません。