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

如何在Swift异步函数中测试await之前的代码?

Swift并发中测试加载状态的解决方法

你的测试用例之所以失败,核心原因是:await sut.getUsers()会等待整个getUsers()函数执行完毕才继续后续代码。而getUsers()里先设置viewState = .loading,紧接着就执行await apiClient.getUsers(),等这个异步请求完成后,viewState会被更新为.normal或.error,所以当你执行断言时,状态已经不是loading了。

下面是几种可行的解决方式:

1. 让模拟API客户端挂起,给测试留断言时间

修改你的MockAPIClient,让它的getUsers()方法可以挂起一段时间,确保测试能在状态更新前完成断言:

class MockAPIClient: APIClientProtocol {
    var shouldDelay = false
    var response: Result<Users, APIError> = .failure(.unknown)
    
    func getUsers() async -> Result<Users, APIError> {
        if shouldDelay {
            // 挂起100毫秒,足够测试完成断言
            try? await Task.sleep(nanoseconds: 100_000_000)
        }
        return response
    }
}

2. 并发执行getUsers和断言操作

不要直接await sut.getUsers(),而是把它放到后台任务中执行,同时立刻检查viewState:

func testShouldShowLoadingViewWhileLoadingUsers() async {
    mocAPIClient.shouldDelay = true
    mocAPIClient.response = Users.stub
    
    // 在后台任务调用getUsers,不等待它完成
    Task { @MainActor in
        await sut.getUsers()
    }
    
    // 立刻断言加载状态
    XCTAssertEqual(sut.viewState, .loading)
}

3. 用XCTestExpectation监听状态变化(更严谨)

如果你的viewState是@Published属性,可以用监听的方式等待loading状态出现,避免依赖固定的延迟时间:

func testShouldShowLoadingViewWhileLoadingUsers() async {
    let loadingExpectation = XCTestExpectation(description: "View state updates to loading")
    mocAPIClient.shouldDelay = true
    mocAPIClient.response = Users.stub
    
    // 监听viewState的变化
    let cancellable = sut.$viewState.sink { state in
        if state == .loading {
            loadingExpectation.fulfill()
        }
    }
    
    // 启动getUsers任务
    Task { @MainActor in
        await sut.getUsers()
    }
    
    // 等待状态变为loading,超时时间1秒
    await fulfillment(of: [loadingExpectation], timeout: 1.0)
    XCTAssertEqual(sut.viewState, .loading)
    
    // 取消监听
    cancellable.cancel()
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 17:14:59