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

ViewModel测试中Success分支未触发@Published属性更新问题

依赖注入下Mock对象测试ViewModel的Success分支未触发问题解决

问题场景

刚接触依赖注入,测试PopularTVViewModel时,调用getShows()后,尽管Mock对象的返回结果已设为Success,但ViewModel中Result的Success分支未及时执行,导致@Published属性popularTV未更新,验证viewModel.popularTV.count == 4的断言失败。已确认Mock对象存在且ViewModel持有其引用,但问题仍存在。

核心原因

ViewModel的getShows()方法中,completion回调内的逻辑被包裹在DispatchQueue.main.async中,而测试代码是同步执行的——断言在异步代码完成前就已执行,此时popularTV还未完成更新。

解决方案

使用XCTestExpectation等待异步任务执行完成,确保断言在popularTV更新后再触发。同时可优化MockManager的计数器调用顺序(非必须,但更符合逻辑)。

修改后的测试代码

import XCTest
@testable import PopularTVViewer

class PopularTVViewerTests: XCTestCase {

    func testPopularTVModel() {
        let mockedManager = MockedPopularTVManager()
        mockedManager.result = .success(mockedManager.mockPopularShows)
        let viewModel = PopularTVViewModel(manager: mockedManager)
        
        // 创建期望,等待异步任务完成
        let loadExpectation = self.expectation(description: "Popular TV shows loaded")
        
        // 监听@Published属性变化,满足条件时触发期望
        let cancellable = viewModel.$popularTV.sink { shows in
            if shows.count == 4 {
                loadExpectation.fulfill()
            }
        }
        
        viewModel.getShows()

        XCTAssertNotNil(viewModel)
        XCTAssertNotNil(mockedManager.result)
        XCTAssertEqual(mockedManager.getPopularShowsCallCounter, 1)
        
        // 等待期望完成,超时时间设为1秒足够测试场景
        waitForExpectations(timeout: 1)
        
        // 异步任务完成后再做最终断言
        XCTAssertEqual(viewModel.popularTV.count, 4)
        
        cancellable.cancel()
    }
}

可选优化:调整MockManager的计数器顺序

将计数器递增放在completion调用之前,更符合"标记调用→返回结果"的逻辑:

func getPopularShows(completion: @escaping (Result<[PopularTV], NetworkError>) -> Void) {
    getPopularShowsCallCounter += 1
    completion(result)
}

补充说明

  • XCTestExpectation是处理异步测试的标准方式,能确保测试代码等待异步逻辑执行完毕再验证结果。
  • 监听@Published属性变化是触发期望最可靠的方式,避免依赖固定等待时间带来的不稳定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 11:50:22