【问题标题】:Swift UI: Unit testing @Published var in an ObservableObject ViewModelSwift UI:在 ObservableObject ViewModel 中对 @Published var 进行单元测试
【发布时间】:2023-04-09 02:14:01
【问题描述】:

所以我正在尝试编写一个单元测试来测试视图模型函数,但它是一个异步函数,并且在我尝试编写的测试中它将同步运行。我在网上看过一些例子,例如

listViewModel.$list.sink { _ in
    XCTAssertEqual(listViewModel.list?.items.count , 1)
    actionExpectation.fulfill()
}
wait(for: [actionExpectation], timeout: 1)

并尝试这里给出的解决方案Unit testing an @ObservableObject in Swift Test Driven Development

我没有任何运气尝试测试它,有什么想法吗?

视图模型

class ListViewModel: ObservableObject {
    @Published var list: List?
    
    let services: Services

    init(services: Services) {
        self.services = services
        getList()
    }

    func getList() {
        if let listService = self.services.resolve(ListService.self) {
            ListService().getList() { [weak self] result in
                switch result {
                    case .success(let dataRecieved):
                        DispatchQueue.main.async {
                            self?.list = dataRecieved
                        }
                    case .failure(let error):
                        print(error)
                }
            }
        }
    }
}

【问题讨论】:

  • 您需要将您的订阅者链存储在Set<AnyCancellable> 中,否则它将在触发之前被释放。此外,您的 ListService 应该被嘲笑;单元测试不应具有外部依赖项,例如网络服务。
  • @Paulw11 抱歉,我对使用 swiftui/combine 进行测试有点陌生。你有没有机会举例说明应该如何使用Set<AnyCancellable>?我的 ListService 已经被嘲笑了,我总是发回一个完成。我刚刚编辑了答案
  • @Paulw11 服务参数传递一个包含模拟列表服务的模拟服务类。它定义调用模拟服务
  • 刚看了看,仍然不确定如何将其应用于@Published var list: List? 不确定您是否可以,但您可以创建一个示例答案吗?我可以在他在 repo.syncObjects() 上调用 .handleEvents 和 .sink 的示例中看到,我是否也必须重写我的服务?因为他没有展示他的同步对象函数是如何声明的

标签: ios swift swiftui xctest


【解决方案1】:

假设你的环境和服务对测试有效,试试这个

let listener = listViewModel.$list.sink { _ in
    XCTAssertEqual(listViewModel.list?.items.count , 1)
    actionExpectation.fulfill()
}
wait(for: [actionExpectation], timeout: 1)

【讨论】:

  • 这几乎是我尝试过的,但是在 viewModel 中的 .success 块完成之前调用了完成: case .success(let dataRecieved): DispatchQueue.main.async { self?.list = dataRecieved } 我可以看到该服务被正常调用并返回完成,但是它不是 viewModels getList 完成而是首先去完成
  • 我唯一能想到的是,当我运行其余部分时,SceneDelegate 创建了 View/ViewModel,然后我在测试中实例化了一个新的 viewModel。只有我能想到的就是导致问题的原因。由于 getLists 被称为 viewModel 被初始化
  • 你试过跳过第一个吗? .dropFirst()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-03-02
  • 1970-01-01
  • 2014-11-07
  • 2019-09-27
  • 2019-12-17
  • 1970-01-01
  • 2020-12-30
相关资源
最近更新 更多