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

M1处理器下异步测试时Publisher未触发完成事件问题

问题分析与解决

问题核心

有一个从文件系统异步加载数据的Combine Publisher,非async标记的测试能正常执行完成,但标记为async的测试会超时失败,且该问题仅在M1设备上必现,Intel设备无此异常。由于需要在测试读取逻辑前await数据保存到文件系统的操作,必须解决async测试下的调度冲突问题。

根因推测

问题出在waitForPublication的实现逻辑上——它依赖XCTestExpectation的阻塞式等待(waitForExpectations),而在async测试的异步上下文里,这种阻塞机制会和Combine的调度队列产生冲突:

  • 非async测试中,测试线程以同步阻塞方式等待,Combine的后台任务能正常调度执行;
  • async测试本身运行在XCTest的异步执行上下文,waitForExpectations的阻塞会打乱线程调度优先级,导致Publisher的任务无法及时被执行,最终触发超时。M1的ARM架构线程调度模型对异步上下文隔离更严格,因此该冲突会被放大并稳定复现,而Intel x86架构的调度容忍度更高,不会表现出异常。

解决方案:用async/await适配Combine

将基于XCTestExpectation的阻塞等待逻辑,替换为Combine原生的async/await支持,避免线程调度冲突。

1. 实现async版本的Publisher等待方法

替换原有的waitForPublication,用Combine的async/await能力实现非阻塞等待:

extension Publisher where Failure == Error {
    func waitForPublication() async throws -> Output {
        return try await self.first()
    }
}

2. 修改async测试代码

用async/await方式等待Publisher结果,不再依赖阻塞式的Expectation:

func testFixed_localSavedLocallyIsUsedWhenAvailable() async {
    let url = testSpecificStoreURL()
    let (publisher, _) = makeSUT(url: url)

    do {
        let expectedData = try await publisher.waitForPublication()
        XCTAssertEqual("Example data", String(data: expectedData, encoding: .utf8))
    } catch {
        XCTFail("Publisher failed with error: \(error)")
    }
}

3. 兼容非async测试(可选)

如果需要保留原有非async测试的逻辑,可以同时保留原waitForPublication方法,让两类测试分别使用对应的等待方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 22:45:32