概要
Swift 5.5 で入った Concurrency を使ったテストで、await
時に想定外のことが起きて結果が返ってこずテストが永遠に終わらないということが起こったので、テストにタイムアウトを設定する方法を調べてまとめました。
動作検証はすべて Xcode 13.2.1 で行いました。
TestPlan を設定する
まず、タイムアウトを設定するために TestPlan を有効にします。タイムアウトの設定のみであればビルド時に特定のコマンドラインオプションを渡すことでも可能なようですが、細かく設定しようと思うと TestPlan を作ってしまった方が便利なのでそちらの方法をとることにします。
Xcode の window 上部の Scheme をクリックして Edit Scheme...
から Test
の Info
タブを開きます。右下の方に Convert to use Test Plans...
というボタンがあるのでこれをクリックします。
3つのオプションが出てくるので、一番上の Create Test Plan from scheme
を選びます。
作成された TestPlan の Configuration
タブを開き TestExecution
> Test Timeouts
を On
にすることでタイムアウトが有効になります。
タイムアウト値の設定
executionTimeAllowance
という XCTestCase
のプロパティを編集することでタイムアウト値を設定することができます。
ドキュメントにあるように、 executionTimeAllowance
の値自体は秒数ですが実際のタイムアウト値は分単位での切り上げになることに注意しましょう。例えば 1
を設定すると1秒の切り上げの1分、 150
を設定すると2分30秒の切り上げの3分でテストがタイムアウトするようになります。この振る舞いは分かりづらいので executionTimeAllowance
の値は 60
120
180
のようにちょうど分単位になるように設定するのがよい気がします。
例えば executionTimeAllowance
を 60
にしてテスト中に 61
秒待つようにすると、期待通りにテストが落ちてくれます。エラーメッセージもなかなかわかりやすいと思います。
以上でテストにタイムアウトを設定することができましたが、すべてのテストでいちいち executionTimeAllowance
を設定するのは大変です。TestPlan の Test Timeouts
の下の Default Test Execution Time Allowance
という項目で executionTimeAllowance
のデフォルト値の設定ができます。以下のように設定すれば、すべてのテストが1分でタイムアウトするようになります。
ちなみに Default Test Execution Time Allowance
自体のデフォルト値は 600
なので、 Test Timeouts
を On
にした時点ですべてのテストが10分でタイムアウトするようになっていたことになります。
Default Test Execution Time Allowance
で決まるタイムアウト値を各テストメソッドごとに上書きしたい場合は executionTimeAllowance
に値を入れることでそちらが優先されます。
まとめ
- テストがなんらかの原因で hang しないようにテストメソッドにタイムアウトを設定するとよい
- TestPlan を有効にして
Test Timeouts
をOn
にすることでテストがタイムアウトするようになる - タイムアウトまでの時間は、 TestPlan の設定の
Default Test Execution Time Allowance
とXCTestCase
のexecutionTimeAllowance
プロパティでそれぞれ設定できる- 後者の設定が優先される
- どちらの設定も単位は秒だが、タイムアウトまでの時間は分単位での切り上げになることに注意