You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 05:13:20