記事


パラメータ化されたテストの実装


テスト関数から複数のテストケースを生成するには、異なる入力パラメータを指定します。





概観


テストによっては、多くの異なる入力に対して実行する必要があります。例えば、列挙型のすべてのケースを検証する必要があるテストなどです。テストライブラリを使用すると、開発者はテスト中に反復処理する 1 つ以上のコレクションを指定し、それらのコレクションの要素をテスト関数に転送できます。特定の引数値セットを持つテスト関数の呼び出しは、テストケースと呼ばれます。


デフォルトでは、テスト関数のテストケースは互いに並列に実行されます。テストの並列化の詳細については、テストを連続してまたは並列に実行する をご覧ください。



値の配列をパラメータ化する


テスト対象となる値を含む配列に対して、n 回テストを実行したいという事はよくあります。以下のテスト関数を考えてみましょう。


enum Food {
  case burger, iceCream, burrito, noodleBowl, kebab
}

@Test("All foods available")
func foodsAvailable() async throws {
  for food: Food in [.burger, .iceCream, .burrito, .noodleBowl, .kebab] {
    let foodTruck = FoodTruck(selling: food)
    #expect(await foodTruck.cook(food))
  }
}

このテスト関数が配列内の値の 1 つで失敗した場合、どの値が失敗したのか不明瞭になる可能性があります。代わりに、テスト関数を様々な入力に対して パラメータ化 することができます。


enum Food {
  case burger, iceCream, burrito, noodleBowl, kebab
}

@Test("All foods available", arguments: [Food.burger, .iceCream, .burrito, .noodleBowl, .kebab])
func foodAvailable(_ food: Food) async throws {
  let foodTruck = FoodTruck(selling: food)
  #expect(await foodTruck.cook(food))
}

パラメータ化のために @Test 属性にコレクションを渡す場合、テストライブラリはコレクション内の各要素を 1 つずつテスト関数の第一引数(そして唯一の引数)として渡します。そして、1 つ以上の入力値でテストが失敗した場合、対応する診断情報によって、どの入力値を検査すべきかを明確に示します。



列挙型の case をパラメータ化する


前の例では、テストする Food の case がハードコードされたリストに含まれています。FoodCaseIterable に準拠した列挙型である場合は、以下のように記述できます。


enum Food: CaseIterable {
  case burger, iceCream, burrito, noodleBowl, kebab
}

@Test("All foods available", arguments: Food.allCases)
func foodAvailable(_ food: Food) async throws {
  let foodTruck = FoodTruck(selling: food)
  #expect(await foodTruck.cook(food))
}

このように、Food 列挙型に新しい case が追加されると、この関数によって自動的にテストされます。



整数の範囲をパラメータ化する


閉じた整数の範囲にわたってテスト関数をパラメータ化することは可能です。


@Test("Can make large orders", arguments: 1 ... 100)
func makeLargeOrder(count: Int) async throws {
  let foodTruck = FoodTruck(selling: .burger)
  #expect(await foodTruck.cook(.burger, quantity: count))
}

注意

0 ..> .max などの非常に大きな範囲では、テストに過度の時間がかかったり、リソースの制約により決して完了しない場合があります。



複数のテスト関数に同じ引数を渡す


同じ引数のコレクションを 2 つ以上のパラメータ化テスト関数に渡したい場合は、引数を別の関数またはプロパティに抽出し、各 @Test 属性に渡すことができます。例えば:


extension Food {
  static var bestSelling: [Food] {
    get async throws { /* ... */ }
  }
}

@Test(arguments: try await Food.bestSelling)
func `Order entree`(food: Food) {
  let foodTruck = FoodTruck()
  #expect(foodTruck.order(food))
}

@Test(arguments: try await Food.bestSelling)
func `Package leftovers`(food: Food) throws {
  let foodTruck = FoodTruck()
  let container = try #require(foodTruck.container(fitting: food))
  try container.add(food)
}

ヒント

argument (引数) に渡す式の前に、try または await の接頭辞を付けることができます。テストライブラリは、関連したテストが実行できると判断した場合にのみ、それらを遅延評価します。


1 つ以上のコレクションでテストする


1 つ以上のコレクションをテストすることも可能です。以下のテスト関数を考えてみましょう。


@Test("Can make large orders", arguments: 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))
}

最初のコレクションの要素はテスト関数の最初の引数として渡され、2 番目のコレクションの要素は 2 番目の引数として渡され、以下同様に続きます。


Food 列挙型に 5 つの case があると仮定すると、このテスト関数は実行されると、料理と注文サイズのあらゆる組み合わせで 500 回(5 x 100)呼び出されます。これらの組み合わせは、コレクションのデカルト派製品と呼ばれます。


上記のような組み合わせ論的な意味を回避するには、zip() を使用します。


@Test("Can make large orders", 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))
}

この zip されたシーケンスは、2 つの引数に「構造化分解」され、自動的に評価のためにテスト関数に渡されます。


この修正されたテスト関数は、zip されたシーケンス内の各タプルに対して 1 回ずつ呼び出されるため、合計 500 回ではなく 5 回呼び出されます。つまり、このテスト関数には、(.burger, 1)、(.burger, 2)、(.burger, 3)、…、(.kebab, 99)、(.kebab, 100) の代わりに (.burger, 1)、(.iceCream, 2)、…、(.kebab, 5) が渡されることになります。


選択したテストケースを実行する


パラメータ化されたテストが特定の要件を満たしている場合、テストライブラリは、そのテストに含まれる特定のテストケースを人々に実行を許可します。これは、テストに多数のケースがあり、そのうちの一部だけが失敗している場合に便利です。これは、失敗したケースを個別に再実行してデバッグできるためです。


選択したテストケースの実行をサポートするには、テストケースの引数を決定論的に一致させる必要があります。パラメータ化されたテスト関数の選択したテストケースを実行しようとすると、テストライブラリはテストケースの各引数が複数の既知のプロトコルのいずれかに準拠しているかどうかを評価し、テストケースのすべての引数がそれらのプロトコルのいずれかに準拠している場合、そのテストケースを選択的に実行できます。以下に、既知のプロトコルを優先順位の高い順に示します。


  1. CustomTestArgumentEncodable

  2. RawValueEncodable に準拠している場合 RawRepresentable

  3. Encodable

  4. IDEncodable に準拠している場合 Identifiable

テストケースのいずれかの引数が上記の要件のいずれかを満たしていない場合、テストケース全体を選択的に実行することはできません。





以下も見よ


テストのパラメータ化


macro Test<C>(String?, any TestTrait..., arguments: C)

値のコレクションに対してパラメーター化されたテストを宣言します。


macro Test<C1, C2>(String?, any TestTrait..., arguments: C1, C2)

2 つの値のコレクションに対してパラメーター化されたテストを宣言します。


macro Test<C1, C2>(String?, any TestTrait..., arguments: Zip2Sequence<C1, C2>)

2 つの圧縮された値のコレクションに対してパラメーター化されたテストを宣言します。


protocol CustomTestArgumentEncodable

パラメーター化されたテストに渡される引数がどのようにコード化されるかをカスタマイズするためのプロトコル。これは、特定の引数を実行するときに照合するために使用されます。


struct Case

パラメータ化された Test からの単一のテストケース。














トップへ












トップへ












トップへ












トップへ












トップへ












トップへ












トップへ












トップへ












トップへ












トップへ












トップへ












トップへ












トップへ












トップへ












トップへ












トップへ












トップへ












トップへ