6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Swift Testingは公式から出たSwift用テストフレームワークです。
XCTestと混在できるため、今日からSwift Testingでテストを書くことができます。

簡単なXCTestからSwift Testingへの書き換え

テスト対象.swift
extension Date {
  var christmas: String {
    "12/25"
  }
}
XCTest.swift
import XCTest

final class DateTests: XCTestCase {
  func testChristmas() {
    XCTAssertEqual(Date.christmas, "12/25")
  }
}
Swift Testing.swift
import Testing

struct DateTests {
  @Test("christmas extensionのテスト")
  func christmas() {
    #expect(Date.christmas == "12/25")
  }
}

構成要素

@Test

テストを宣言するマクロ。関数の前に追加する。
XCTestではXCTestCaseを継承し、関数名の頭にtestをつける。

@Suite

複数のテストをまとめるマクロ。
テスト関数を含むクラスが自動的にテストスイート(複数のテストをまとめたもの)になる。

struct DateTests { // 自動的にテストスイートになる。
  @Test func christmas() {
    //...
  }
}

表示名やtraitを付与したい場合は@Suiteマクロを使用する。

@Suite(.timeLimit(.minutes(60))
struct DateTests {
  @Test func christmas() {
    //...
  }
}

期待値の確認

#expect(_:_:sourceLocation:)または#require(_:_:sourceLocation:)を使用し評価します。

XCTest.swift
final class EventTests: XCTestCase {
  func finalYearlyEvents() throws {
    XCTAssertNotNil(events.last)
    XCTAssertEqual(events.last, .christmas)
  }
}
Swift Testing.swift
struct EventTests {
  @Test func finalYearlyEvents() throws {
    try #require(events.last != nil)
    #expect(events.last == .christmas)
  }
}

Traits

テストやテストスイートに特性を付与することで、テストに注釈を付けたり動作をカスタムすることができる。
それぞれの使い方は公式ドキュメントに詳しく書かれているので、概要とリンクのみとします。

  • enabled/disabled
    テストを条件付きで有効または無効にする。
  • timeLimit
    テストの制限時間を設定する。
    複数の制限時間が設定されている場合、一番短いものが適応される。
    テストスイートに制限時間を宣言すると、そのスイート内全てのテストスイートと関数に適応される。
  • serialized
    並列実行/順次実行を制御します。
  • bug
    バグとテストを関連つけます。
  • tags
    テストやテストスイートにタグをつけることができる。
  • コメント(//,/**/)
    コードにコメントを追加しテスト結果に情報を提供する。

新しい機能

パラメイトライズ

Swift Testing特有の機能です。異なるパラメータを外部から注入することで、1つのテスト関数から複数のテストを生成することができます。

enum Event {
  case valentine, halloween, christmas

  var day: String { ... }
}

XCTestでこのようなテストがあるとします。

XCTest.swift
final class EventTests: XCTestCase {
  func testDay() {
    XCTAssertEqual(Event.valentine, "2/14")
    XCTAssertEqual(Event.halloween, "10/31")
    XCTAssertEqual(Event.christmas, "12/25")
  }
}

この場合仮にテストが失敗したら再実行はtestDay単位でしかできず、3つの判定が再度走ることとなります。
一方でこのテストをSwift Testingのパラメイトライズを活用するとこのように書き換えられます。

Swift Testing.swift
struct EventTests {
  @Test(arguments: [
    (Event.valentine, "2/14"),
    (Event.halloween, "10/31"),
    (Event.christmas, "12/25")
  ])
  func testDay(event: Event, expected: String) {
    #expect(event.day == expected)
  }
}

テストの実行はtestDayが各パラメータで3回実行される形になります。どのパラメータで失敗したか一目でわかり、失敗したパラメータのみ再実行できます。

引数はargumentsで指定した順にテスト関数で参照できます。

並列実行と順次実行

テストスイートやテスト関数は指定しない場合、自動で並列実行されます。
順次実行したい場合はserializedトレイトを付与します。

※ テスト関数に付与する場合は、テスト関数がパラメイトライズを使用していなければ効果はありません。

Swift Testing.swift
struct EventTests {
  @Test(.serialized, arguments: [
    (Event.valentine, "2/14"),
    (Event.halloween, "10/31"),
    (Event.christmas, "12/25")
  ])
  func testDay(event: Event, expected: String) {
    #expect(event.day == expected)
  }
}

これにより、3ケース並列してテストされず、前のテストを待ってから次のテストが開始されます。

エラーのテスト

withKnownIssueを使用すると、既知の問題のみが発生した場合テストは失敗ではなく成功と判定されます。
※既知のエラーに関しては#expect(throws:)ではなくwithKnownIssueを使用することが推奨されます。

struct EventTests {
  @Test func finalYearlyEvents() throws {
    try #require(events.last != nil)
    #expect(events.last == .christmas) // これが既知のエラーの場合
  }
}

struct EventTests {
  @Test func finalYearlyEvents() throws {
    try #require(events.last != nil)
    withKnownIssue("最後のイベントは年越しです。") {
      #expect(events.last == .christmas)
    }
  }
}

参考

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?