ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
Swift Testingについて
Swiftを使用してコードをテストするための新しいパッケージ、Swift Testingが登場しました。このパッケージの新しいパワフルなAPIの構成要素、一般的なテストワークフローでの応用方法、XCTestおよびオープンソースSwiftとの関連性について解説します。
関連する章
- 0:00 - Introduction
- 0:59 - Agenda
- 1:20 - Building blocks
- 1:58 - Building blocks: @Test functions
- 3:07 - Building blocks: Expectations (#expect and #require)
- 6:02 - Building blocks: Traits
- 6:49 - Building blocks: @Suite types
- 8:34 - Building blocks: Designed for Swift
- 9:14 - Common workflows
- 9:29 - Common workflows: Tests with conditions
- 10:56 - Common workflows: Tests with common characteristics
- 13:13 - Common workflows: Tests with different arguments
- 17:35 - Swift Testing and XCTest
- 21:52 - Open source
- 23:29 - Wrap up
リソース
- Adding tests to your Xcode project
- Forum: Developer Tools & Services
- Improving code assessment by organizing tests into test plans
- Running tests and interpreting results
- Swift Testing
- Swift Testing GitHub repository
- Swift Testing vision document
関連ビデオ
WWDC24
-
ダウンロードArray
-
-
1:54 - Write your first @Test function
import Testing @Test func videoMetadata() { // ... }
-
2:35 - Validate an expected condition using #expect
import Testing @testable import DestinationVideo @Test func videoMetadata() { let video = Video(fileName: "By the Lake.mov") let expectedMetadata = Metadata(duration: .seconds(90)) #expect(video.metadata == expectedMetadata) }
-
4:24 - Fix a bug in the code being tested
// In `Video.init(...)` self.metadata = Metadata(forContentsOfUrl: url)
-
6:06 - Add a display name to a @Test function
@Test("Check video metadata") func videoMetadata() { let video = Video(fileName: "By the Lake.mov") let expectedMetadata = Metadata(duration: .seconds(90)) #expect(video.metadata == expectedMetadata) }
-
6:58 - Add a second @Test function
@Test func rating() async throws { let video = Video(fileName: "By the Lake.mov") #expect(video.contentRating == "G") }
-
7:18 - Organize @Test functions into a suite type
struct VideoTests { @Test("Check video metadata") func videoMetadata() { let video = Video(fileName: "By the Lake.mov") let expectedMetadata = Metadata(duration: .seconds(90)) #expect(video.metadata == expectedMetadata) } @Test func rating() async throws { let video = Video(fileName: "By the Lake.mov") #expect(video.contentRating == "G") } }
-
8:04 - Factor a common value into a stored property in the suite
struct VideoTests { let video = Video(fileName: "By the Lake.mov") @Test("Check video metadata") func videoMetadata() { let expectedMetadata = Metadata(duration: .seconds(90)) #expect(video.metadata == expectedMetadata) } @Test func rating() async throws { #expect(video.contentRating == "G") } }
-
9:32 - Specify a runtime condition trait for a @Test function
@Test(.enabled(if: AppFeatures.isCommentingEnabled)) func videoCommenting() { // ... }
-
9:49 - Unconditionally disable a @Test function
@Test(.disabled("Due to a known crash")) func example() { // ... }
-
10:15 - Include a bug trait with a URL along with other traits
@Test(.disabled("Due to a known crash"), .bug("example.org/bugs/1234", "Program crashes at <symbol>")) func example() { // ... }
-
10:33 - Conditionalize a test based on OS version
@Test @available(macOS 15, *) func usesNewAPIs() { // ... }
-
10:42 - Prefer @available on @Test function instead of #available within the function
// ❌ Avoid checking availability at runtime using #available @Test func hasRuntimeVersionCheck() { guard #available(macOS 15, *) else { return } // ... } // ✅ Prefer @available attribute on test function @Test @available(macOS 15, *) func usesNewAPIs() { // ... }
-
11:22 - Add a tag to a @Test function
@Test(.tags(.formatting)) func rating() async throws { #expect(video.contentRating == "G") }
-
11:48 - Add another data formatting-related test with the same tag
@Test(.tags(.formatting)) func formattedDuration() async throws { let videoLibrary = try await VideoLibrary() let video = try #require(await videoLibrary.video(named: "By the Lake")) #expect(video.formattedDuration == "0m 19s") }
-
11:56 - Group related tests into a sub-suite
struct MetadataPresentation { let video = Video(fileName: "By the Lake.mov") @Test(.tags(.formatting)) func rating() async throws { #expect(video.contentRating == "G") } @Test(.tags(.formatting)) func formattedDuration() async throws { let videoLibrary = try await VideoLibrary() let video = try #require(await videoLibrary.video(named: "By the Lake")) #expect(video.formattedDuration == "0m 19s") } }
-
12:05 - Move common tags trait to @Suite attribute, so the suite's @Test functions will inherit the tag
@Suite(.tags(.formatting)) struct MetadataPresentation { let video = Video(fileName: "By the Lake.mov") @Test func rating() async throws { #expect(video.contentRating == "G") } @Test func formattedDuration() async throws { let videoLibrary = try await VideoLibrary() let video = try #require(await videoLibrary.video(named: "By the Lake")) #expect(video.formattedDuration == "0m 19s") } }
-
13:27 - Example of some repetitive tests which can be consolidated into a parameterized @Test function
struct VideoContinentsTests { @Test func mentionsFor_A_Beach() async throws { let videoLibrary = try await VideoLibrary() let video = try #require(await videoLibrary.video(named: "A Beach")) #expect(!video.mentionedContinents.isEmpty) #expect(video.mentionedContinents.count <= 3) } @Test func mentionsFor_By_the_Lake() async throws { let videoLibrary = try await VideoLibrary() let video = try #require(await videoLibrary.video(named: "By the Lake")) #expect(!video.mentionedContinents.isEmpty) #expect(video.mentionedContinents.count <= 3) } @Test func mentionsFor_Camping_in_the_Woods() async throws { let videoLibrary = try await VideoLibrary() let video = try #require(await videoLibrary.video(named: "Camping in the Woods")) #expect(!video.mentionedContinents.isEmpty) #expect(video.mentionedContinents.count <= 3) } // ...and more, similar test functions }
-
14:07 - Refactor several similar tests into a parameterized @Test function
struct VideoContinentsTests { @Test("Number of mentioned continents", arguments: [ "A Beach", "By the Lake", "Camping in the Woods", "The Rolling Hills", "Ocean Breeze", "Patagonia Lake", "Scotland Coast", "China Paddy Field", ]) func mentionedContinentCounts(videoName: String) async throws { let videoLibrary = try await VideoLibrary() let video = try #require(await videoLibrary.video(named: videoName)) #expect(!video.mentionedContinents.isEmpty) #expect(video.mentionedContinents.count <= 3) } }
-
// Using a for…in loop to repeat a test (not recommended) @Test func mentionedContinentCounts() async throws { let videoNames = [ "A Beach", "By the Lake", "Camping in the Woods", ] let videoLibrary = try await VideoLibrary() for videoName in videoNames { let video = try #require(await videoLibrary.video(named: videoName)) #expect(!video.mentionedContinents.isEmpty) #expect(video.mentionedContinents.count <= 3) } }
-
17:15 - Refactor a test using a for…in loop into a parameterized @Test function
@Test(arguments: [ "A Beach", "By the Lake", "Camping in the Woods", ]) func mentionedContinentCounts(videoName: String) async throws { let videoLibrary = try await VideoLibrary() let video = try #require(await videoLibrary.video(named: videoName)) #expect(!video.mentionedContinents.isEmpty) #expect(video.mentionedContinents.count <= 3) }
-
22:47 - A newly-created Swift package with two simple @Test functions
import Testing @testable import MyLibrary @Test func example() throws { #expect("abc" == "abc") } @Test func failingExample() throws { #expect(123 == 456) }
-
22:56 - Running all tests for the package from Terminal
> swift test
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。