테스트가 해결하는 도전 과제들:
#expect 매크로는 단순한 참/거짓 검증 외에도 다양한 복잡한 검증을 간결하게 처리합니다.import Testing
@Test func brewTeaSuccessfully() throws {
let teaLeaves = TeaLeaves(name: "EarlGrey", optimalBrewTime: 4)
let cupOfTea = try teaLeaves.brew(forMinutes: 3)
#expect(cupOfTea.quality == .perfect)
}
import Testing
@Test func brewTeaError() throws {
let teaLeaves = TeaLeaves(name: "EarlGrey", optimalBrewTime: 4)
#expect(throws: BrewingError.self) {
try teaLeaves.brew(forMinutes: 200)
}
}
BrewingError.self#expect { try teaLeaves.brew(forMinutes: 3) } throws: { error in
guard let error = error as? BrewingError,
case let .needsMoreTime(optimalBrewTime) = error else { return false }
return optimalBrewTime == 4
}
#require를 사용withKnownIssue { ... }로 감싸 관리import Testing
@Test func softServeIceCreamInCone() throws {
withKnownIssue {
try softServeMachine.makeSoftServe(in: .cone)
}
}
CustomTestStringConvertible 프로토콜을 구현하면 가독성이 큰 폭 개선된다.struct SoftServe: CustomTestStringConvertible {
let flavor: Flavor
let container: Container
var testDescription: String { "\(flavor) in a \(container)" }
}
enum Ingredient: CaseIterable { case rice, potato, lettuce, egg }
@Test(arguments: Ingredient.allCases)
func cook(_ ingredient: Ingredient) async throws {
#expect(ingredient.isFresh)
let result = try cook(ingredient)
try #require(result.isDelicious)
}
enum Ingredient: CaseIterable { ... }
enum Dish: CaseIterable { ... }
@Test(arguments: Ingredient.allCases, Dish.allCases)
func cook(_ ingredient: Ingredient, into dish: Dish) async throws {
#expect(ingredient.isFresh)
let result = try cook(ingredient)
try #require(result.isDelicious)
try #require(result == dish)
}
@Test(arguments: zip(...))@Suite 어노테이션으로 여러 테스트 함수/모음을 구조화@Suite("Various desserts") struct DessertTests {
@Suite struct WarmDesserts { ... }
@Suite struct ColdDesserts { ... }
}
extension Tag {
@Tag static var caffeinated: Self
@Tag static var chocolatey: Self
}
@Suite(.tags(.caffeinated)) struct DrinkTests { ... }
@Test(.tags(.chocolatey)) func mochaIngredientProportion() { ... }
.serialized 지정@Suite("Cupcake tests", .serialized) struct CupcakeTests { ... }
@Test func bakeCookies() async throws {
let cookies = await Cookie.bake(count: 10)
try await eat(cookies, with: .milk)
}
@Test func bakeCookies() async throws {
let cookies = await Cookie.bake(count: 10)
try await withCheckedThrowingContinuation { continuation in
eat(cookies, with: .milk) { result, error in
if let result { continuation.resume(returning: result) }
else { continuation.resume(throwing: error) }
}
}
}
confirmation("label", expectedCount:) 활용 가능@Test func bakeCookies() async throws {
let cookies = await Cookie.bake(count: 10)
try await confirmation("Ate cookies", expectedCount: 10) { ateCookie in
try await eat(cookies, with: .milk) { cookie, crumbs in
#expect(!crumbs.in(.milk))
ateCookie() // 콜백마다 호출
}
}
}
expectedCount: 0도 지정 가능