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

为UIViewControllerRepresentable写单元测试遇Context初始化错误

解决UIViewControllerRepresentableContext无法初始化的测试问题

你遇到的错误是因为UIViewControllerRepresentableContext的初始化器是SwiftUI内部实现,对外不可访问,无法直接在测试代码中实例化。以下是两种可行的解决方案:

方案1:抽离核心逻辑到可测试方法

将makeUIViewController中创建和配置视图控制器的逻辑抽成独立方法,绕过对上下文的依赖,直接测试核心逻辑:

修改DocumentPicker结构体

struct DocumentPicker: UIViewControllerRepresentable {
    class Coordinator: NSObject, UIDocumentPickerDelegate {
        var parent: DocumentPicker

        init(parent: DocumentPicker) {
            self.parent = parent
        }

        func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
            parent.didPickDocuments(urls)
        }

        func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
            parent.didCancel()
        }
    }

    var didPickDocuments: ([URL]) -> Void
    var didCancel: () -> Void

    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }

    func makeUIViewController(context: Context) -> UIDocumentPickerViewController {
        makePicker(with: context.coordinator)
    }
    
    // 抽离的方法,直接接收协调器参数
    func makePicker(with coordinator: Coordinator) -> UIDocumentPickerViewController {
        let picker = UIDocumentPickerViewController(forOpeningContentTypes: [.item], asCopy: true)
        picker.delegate = coordinator
        picker.allowsMultipleSelection = true
        return picker
    }

    func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: Context) {}
}

修改测试用例

class DocumentPickerCreationTests: XCTestCase {

    func testMakeCoordinator() {
        let documentPicker = DocumentPicker(didPickDocuments: { _ in }, didCancel: { })
        let coordinator = documentPicker.makeCoordinator()
        XCTAssertNotNil(coordinator)
        XCTAssertTrue(coordinator is DocumentPicker.Coordinator)
    }

    func testMakeUIViewController() {
        let documentPicker = DocumentPicker(didPickDocuments: { _ in }, didCancel: { })
        let coordinator = documentPicker.makeCoordinator()
        // 直接调用抽离的方法,无需创建上下文
        let viewController = documentPicker.makePicker(with: coordinator)
        XCTAssertTrue(viewController is UIDocumentPickerViewController)
        XCTAssertEqual(viewController.delegate as? DocumentPicker.Coordinator, coordinator)
        XCTAssertTrue(viewController.allowsMultipleSelection)
    }
}

方案2:测试目标中扩展上下文初始化器

如果不想修改原业务代码,可以在测试文件中给UIViewControllerRepresentableContext添加测试专用的初始化器,需要先导入你的App模块并启用测试访问:

@testable import YourAppModule

extension UIViewControllerRepresentableContext where Coordinator == DocumentPicker.Coordinator {
    // 自定义初始化器,使用默认环境和事务值
    init(coordinator: Coordinator) {
        self.init(coordinator: coordinator, environment: EnvironmentValues(), transaction: Transaction())
    }
}

添加这个扩展后,你原来的测试代码就可以正常运行,无需其他修改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 00:44:53