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

单元测试中如何获取传递给变量类型Completion Handler的值?

如何捕获变量式Completion Handler的返回值用于单元测试

我来帮你搞定这个单元测试里捕获onCompletion参数的问题!你这里把Completion Handler做成了实例变量onCompletion,确实和常规闭包传参的场景不太一样,但测试起来其实很简单,核心思路就是用一个测试专用的闭包替换掉原有的onCompletion,在闭包内部把收到的ResultType值存下来,之后就能轻松断言校验了。

具体实现步骤(基于XCTest)

首先我们需要在测试类里准备一个变量来存储捕获到的结果,然后替换目标对象的onCompletion为我们的测试闭包,最后调用目标方法并断言结果:

import XCTest
@testable import YourAppModule // 替换成你的实际模块名

// 假设你的网络类叫NetworkManager,请替换成实际类名
class NetworkManagerTests: XCTestCase {
    var testNetworkManager: NetworkManager!
    // 用来存储捕获到的Completion结果
    var capturedResult: ResultType?
    
    override func setUp() {
        super.setUp()
        // 初始化测试对象
        testNetworkManager = NetworkManager()
        // 替换onCompletion为测试用闭包,捕获传入的Result
        testNetworkManager.onCompletion = { [weak self] result in
            self?.capturedResult = result
        }
    }
    
    override func tearDown() {
        // 测试后清空变量,避免影响其他测试用例
        capturedResult = nil
        testNetworkManager = nil
        super.tearDown()
    }
    
    func testFinishedWithErrorsReturnsNetworkNotReachableError() {
        // 调用你要测试的finished方法,传入测试用错误
        let testErrors = [NSError(domain: "TestErrorDomain", code: 999, userInfo: nil)]
        testNetworkManager.finished(testErrors)
        
        // 开始断言校验
        XCTAssertNotNil(capturedResult, "Completion handler should have been triggered")
        
        // 校验结果是否为预期的failure类型
        guard case .failure(let error) = capturedResult else {
            XCTFail("Expected a failure result but got success")
            return
        }
        
        // 进一步校验错误的具体类型
        guard let eComError = error as? EComError,
              case .networkError(.notReachable) = eComError else {
            XCTFail("Expected EComError.networkError(.notReachable) but got \(error)")
            return
        }
    }
}

注意事项

  • 弱引用self:测试闭包里用[weak self]是为了避免测试类和测试对象之间的循环引用,虽然测试用例的生命周期很短,但养成这个习惯能避免潜在的内存问题。
  • 异步场景处理:如果你的onCompletion是异步触发的(比如网络请求真正完成后才调用),那需要用XCTestExpectation来等待结果,示例如下:
func testAsyncNetworkCallReturnsResult() {
    let completionExpectation = expectation(description: "Wait for async completion")
    
    testNetworkManager.onCompletion = { [weak self] result in
        self?.capturedResult = result
        completionExpectation.fulfill() // 标记等待完成
    }
    
    // 触发异步网络操作
    testNetworkManager.startAsyncNetworkRequest()
    
    // 等待最多5秒,超时则测试失败
    waitForExpectations(timeout: 5, handler: nil)
    
    // 之后对capturedResult进行断言,逻辑和同步场景一致
    XCTAssertNotNil(capturedResult)
    // ...其他断言
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 04:16:05