XCode 16.3 日本語化計画
テストプロセスを終了する可能性のある機能をテストするには、終了テストを使用します。
あなたのコードには、precondition()、fatalError()、または現在のプロセスを終了させる可能性のあるその他の関数の呼び出しが含まれている可能性があります。例えば:
extension Customer { func eat(_ food: consuming some Food) { precondition(food.isDelicious, "Tasty food only!") precondition(food.isNutritious, "Healthy food only!") ... } }
この関数では、food.isDelicious または food.isNutritious が false の場合、前提条件が満たされず、Swift はプロセスを強制的に終了します。上記のような前提条件を検証し、あなたの関数が無効な入力を正しく catch していることを確認するための終了テストを記述できます。
終了テストを作成するには、expect(processExitsWith:observing:_:sourceLocation:performing:) または require(processExitsWith:observing:_:sourceLocation:performing:) マクロのいずれかを呼び出します。
@Test func `Customer won't eat food unless it's delicious`() async { let result = await #expect(processExitsWith: .failure) { var food = ... food.isDelicious = false Customer.current.eat(food) } }
マクロにあなたが渡すクロージャまたは関数の参照は、終了テストの 本体 となります。実行時に終了テストが実行されると、テストライブラリは現在のプロセスと同じ実行ファイルを持つ新しいプロセスを開始します。その後、現在のタスクは (await と同様に) 一時停止され、子プロセスが終了するまで待機します。
親プロセスは終了テストの本体を呼び出しません。代わりに、子プロセスは終了テストの本体を main() 関数として扱い、直接呼び出します。
@Test func `Customer won't eat food unless it's nutritious`() async {
let isNutritious = false
await #expect(processExitsWith: .failure) {
var food = ...
food.isNutritious = isNutritious // ❌ ERROR: trying to capture state here
Customer.current.eat(food)
}
}
子プロセスが終了する前に本体が戻った場合、プロセスは main() が正常に戻ったかのように終了します。本体がエラーを throw した場合、Swift はそれを main() から throw されたかのように処理し、プロセスを強制的に異常終了させます。
終了テストを作成するときは、ExitTest.Condition のインスタンスを渡して、子プロセスがどのように終了するかを指定します。
子プロセスが終了すると、親プロセスは再開し、子プロセスの終了ステータスと、あなたが渡した想定終了条件を比較します。一致した場合、終了テストは成功します。一致しない場合、終了テストは失敗し、テストライブラリは問題を記録します。
expect(processExitsWith:observing:_:sourceLocation:performing:) マクロと require(processExitsWith:observing:_:sourceLocation:performing:) マクロは、子プロセスの状態に関する情報を含む ExitTest.Result のインスタンスを返します。
デフォルトでは、子プロセスは標準出力または標準エラーストリームなしで構成されます。あなたのテストでこれらのストリームの内容を確認する必要がある場合は、対応する ExitTest.Result プロパティへのキーパスをマクロに渡します。
extension Customer { func eat(_ food: consuming some Food) { print("Let's see if I want to eat \(food)...") precondition(food.isDelicious, "Tasty food only!") precondition(food.isNutritious, "Healthy food only!") ... } } @Test func `Customer won't eat food unless it's delicious`() async { let result = await #expect( processExitsWith: .failure, observing: [\.standardOutputContent] ) { var food = ... food.isDelicious = false Customer.current.eat(food) } if let result { #expect(result.standardOutputContent.contains(UInt8(ascii: "L"))) } }
テストライブラリは、\.exitStatus を監視しない場合でも、常に ExitStatus を子プロセスの実際の終了ステータス (システムによって報告されたとおり) に設定します。
テストプロセスを終了する可能性のある機能をテストするには、テストの終了を使用します。
式によってプロセスが与えられた方法で終了することを確認します。
式によってプロセスが与えられた方法で終了することを確認し、終了しなかった場合はエラーを throw します。
プロセスが終了時に報告する可能性のあるステータスを記述する列挙型。
終了テストを記述する型。