如何用Swift Testing测试枚举断言失败(替代XCTExpectFailure)
Swift枚举合法性检查与Swift Testing测试方案
先贴出你定义的枚举代码:
enum Schedule { case daily /// Every nth day. The interval between days must be > 1 else error. case interval(interval: Int) func description() -> String { switch self { case .daily: return "Daily" case .interval(let interval): switch interval { case ...(1): assertionFailure("Interval must be > 1 day.") return "No good interval" default: return "Good interval" } } } }
核心需求&问题
- 要对
.interval传入的参数做合法性检查,最好在创建枚举时就拦截无效值,同时保留简洁的Swift语法,不想写初始化器让开发者主动调用 - 当前用
assertionFailure处理无效参数,需要知道怎么用Swift Testing测试这个枚举,替代XCTest里的XCTExpectFailure
一、Swift Testing中测试断言失败的方法
在Swift Testing框架里,测试触发断言失败的代码,有两种直接的方式:
1. 捕获断言错误验证行为
断言失败本质会抛出AssertionError,你可以用#expect(throws:)直接捕获这个错误,验证代码确实触发了断言:
import Testing @Suite("Schedule枚举测试") struct ScheduleTests { @Test("无效interval触发断言失败") func testInvalidInterval() { #expect(throws: AssertionError.self) { let _ = Schedule.interval(interval: 1).description() } } @Test("有效interval返回正确描述") func testValidInterval() { let schedule = Schedule.interval(interval: 3) #expect(schedule.description() == "Good interval") } @Test("daily case返回正确描述") func testDailyCase() { #expect(Schedule.daily.description() == "Daily") } }
2. 直接验证断言触发
如果不需要捕获具体错误,只是要确认代码会触发断言,用assertFails方法更简洁:
@Test("无效interval触发断言") func testInvalidIntervalAssertion() { assertFails { let _ = Schedule.interval(interval: 0).description() } }
二、优化枚举合法性检查的可选方案
如果想在创建枚举时就拦截无效值,又不想让开发者手动调用初始化器,可以试试这两种方案:
方案1:静态方法返回可选值
用静态方法包装.interval的创建逻辑,无效值返回nil,同时保留原case的语法(需要绕过检查时仍能直接用):
enum Schedule { case daily case interval(interval: Int) static func interval(_ value: Int) -> Schedule? { guard value > 1 else { return nil } return .interval(interval: value) } // 原description方法不变 }
这样开发者可以用Schedule.interval(3)拿到合法实例,Schedule.interval(1)返回nil,测试时直接验证返回值即可。
方案2:强制合法的枚举实例
如果要完全禁止创建无效的.interval实例,可以把case设为私有,用静态方法暴露创建逻辑,无效值触发preconditionFailure:
enum Schedule { case daily private case intervalValue(Int) static var daily: Schedule { .daily } static func interval(_ value: Int) -> Schedule { precondition(value > 1, "Interval must be > 1 day.") return .intervalValue(value) } func description() -> String { switch self { case .daily: return "Daily" case .intervalValue(let interval): return "Good interval" } } }
这种方式下,开发者只能通过Schedule.interval(3)创建实例,测试时同样可以用上面的Swift Testing方法捕获断言/前置条件失败。
内容的提问来源于stack exchange,提问作者Womble
相关产品推荐
相关产品推荐

