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

如何在单元测试中创建Live Activity对象?遇ActivityAuthorizationError.unsupportedTarget错误

解决单元测试中Mock ActivityKit Live Activity的unsupportedTarget错误

问题根源

ActivityKit是Apple原生框架,未提供针对测试目标的编译版本,直接在单元测试中调用其API会触发ActivityAuthorizationError.unsupportedTarget错误,同时也无法将其标记为可测试模块(对应Module 'ActivityKit' was not compiled for testing错误)。主应用能正常运行是因为框架仅针对正式运行环境编译。

解决方案:依赖抽象+Mock隔离

通过抽象层封装ActivityKit的调用,在单元测试中用Mock实现替代真实框架,彻底隔离系统依赖:

  1. 抽象ActivityKit操作协议
    定义协议封装你需要用到的Live Activity相关功能,避免直接耦合ActivityKit API:

    protocol LiveActivityHandler {
        func requestAuthorization() async throws -> ActivityAuthorizationStatus
        func startActivity(attributes: some ActivityAttributes, contentState: attributes.ContentState) throws -> Activity<some ActivityAttributes>
        // 添加你业务中用到的其他方法,比如结束Activity等
    }
    
  2. 实现生产环境的真实 handler
    在主应用中创建协议的真实实现,直接调用ActivityKit的原生API:

    class RealLiveActivityHandler: LiveActivityHandler {
        func requestAuthorization() async throws -> ActivityAuthorizationStatus {
            return try await Activity.requestAuthorization()
        }
        
        func startActivity(attributes: some ActivityAttributes, contentState: attributes.ContentState) throws -> Activity<some ActivityAttributes> {
            return try Activity.request(attributes: attributes, contentState: contentState)
        }
    }
    
  3. 编写测试用的Mock实现
    创建Mock类实现协议,无需调用真实ActivityKit API,直接返回测试所需的状态或错误:

    class MockLiveActivityHandler: LiveActivityHandler {
        // 可自定义测试返回的授权状态
        var mockAuthorizationStatus: ActivityAuthorizationStatus = .authorized
        // 标记方法是否被调用,用于验证逻辑
        var didCallStartActivity = false
        
        func requestAuthorization() async throws -> ActivityAuthorizationStatus {
            return mockAuthorizationStatus
        }
        
        func startActivity(attributes: some ActivityAttributes, contentState: attributes.ContentState) throws -> Activity<some ActivityAttributes> {
            didCallStartActivity = true
            // 可根据测试场景抛出错误或返回模拟对象
            // 例:模拟授权失败场景
            // throw ActivityKit.ActivityAuthorizationError.denied
            
            // 注意:Activity是系统类无法直接实例化,若需要返回实例,可进一步封装Activity的功能为子协议
            fatalError("如需返回实例,请封装Activity功能为子协议并实现Mock")
        }
    }
    
  4. 业务代码注入依赖
    在业务逻辑类中通过构造函数注入LiveActivityHandler,默认使用真实实现,测试时替换为Mock:

    class LiveActivityService {
        private let activityHandler: LiveActivityHandler
        
        // 默认使用真实handler,生产环境无需额外配置
        init(activityHandler: LiveActivityHandler = RealLiveActivityHandler()) {
            self.activityHandler = activityHandler
        }
        
        func launchActivity() async throws {
            let status = try await activityHandler.requestAuthorization()
            guard status == .authorized else {
                throw LiveActivityError.unauthorized
            }
            try activityHandler.startActivity(attributes: MyActivityAttributes(), contentState: MyContentState())
        }
    }
    
  5. 单元测试中使用Mock
    在测试用例中初始化业务类时传入Mock实现,完全隔离ActivityKit:

    func testLaunchActivity_WhenUnauthorized_ThrowsError() async {
        let mockHandler = MockLiveActivityHandler()
        mockHandler.mockAuthorizationStatus = .denied
        let service = LiveActivityService(activityHandler: mockHandler)
        
        await XCTAssertThrowsError(try await service.launchActivity()) { error in
            XCTAssertEqual(error as? LiveActivityError, .unauthorized)
        }
    }
    

关键注意事项

  • 永远不要在单元测试中直接调用ActivityKit的API,所有依赖必须通过抽象层Mock。
  • 若需要模拟Activity实例的行为,需进一步封装Activity的功能为子协议,再实现对应的Mock类。

内容的提问来源于stack exchange,提问作者jakub1984

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 16:11:12