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

Swift单元测试中如何Mock AVFoundation的授权方法

问题描述

我使用静态函数AVCaptureDevice.authorizationStatus(for: .video)来检查相机权限。
在Objective-C中,使用OCMock很容易对该方法进行Mock,强制其返回.authorized枚举值。但OCMock并不支持Swift,请问该如何实现该需求?

补充说明

请不要关闭本问题,之前给出的「Swift单元测试Mock类静态方法」相关的重复问题参考方案无法解决该问题:那些方案仅适用于开发者自定义的类,不适用于系统API,无法生效。

解决方案

Swift 基于静态派发的特性,无法像OC那样直接通过runtime swizzle替换系统类静态方法的实现,目前行业内通用的处理方式是加一层协议抽象隔离系统API依赖,不需要借助第三方Mock框架就能实现测试控制,具体步骤如下:

  • 定义相机权限检查的抽象协议,把业务需要用到的权限相关接口统一收拢
protocol CameraAuthorizationService {
    func currentVideoAuthStatus() -> AVAuthorizationStatus
    func requestVideoAccess(completion: @escaping (Bool) -> Void)
}
  • 实现默认的权限服务类,内部调用真实的系统AVFoundation API
struct SystemCameraAuthService: CameraAuthorizationService {
    func currentVideoAuthStatus() -> AVAuthorizationStatus {
        AVCaptureDevice.authorizationStatus(for: .video)
    }
    
    func requestVideoAccess(completion: @escaping (Bool) -> Void) {
        AVCaptureDevice.requestAccess(for: .video, completionHandler: completion)
    }
}
  • 业务代码中避免直接硬编码调用AVCaptureDevice的静态方法,转而依赖上述协议,通过依赖注入传入具体实现,默认使用系统真实实现即可
class CameraUseViewController: UIViewController {
    private let authService: CameraAuthorizationService
    
    init(authService: CameraAuthorizationService = SystemCameraAuthService()) {
        self.authService = authService
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        self.authService = SystemCameraAuthService()
        super.init(coder: coder)
    }
    
    func whenViewDidLoadCheckAuth() {
        let status = authService.currentVideoAuthStatus()
        // 后续业务逻辑根据状态处理
    }
}
  • 单元测试场景下,自定义Mock实现,自由控制返回的权限状态即可,完全不需要触碰系统API
class MockCameraAuthService: CameraAuthorizationService {
    var mockStatus: AVAuthorizationStatus = .notDetermined
    var mockRequestGranted: Bool = false
    
    func currentVideoAuthStatus() -> AVAuthorizationStatus {
        mockStatus
    }
    
    func requestVideoAccess(completion: @escaping (Bool) -> Void) {
        completion(mockRequestGranted)
    }
}

// 测试用例示例
func testAuthorizedStateCameraFlow() {
    let mockAuth = MockCameraAuthService()
    mockAuth.mockStatus = .authorized
    let vc = CameraUseViewController(authService: mockAuth)
    // 验证授权状态下的页面逻辑是否符合预期
}

如果项目存量代码太多,暂时没法全量重构为协议注入的形式,可以退而求其次使用XCTest UI测试能力,通过启动参数控制测试环境下的权限状态,但这种方式运行速度慢、稳定性差,仅适合作为临时方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 07:06:19