在 Swift 测试驱动开发中对 @ObservableObject 进行单元测试

Posted

技术标签:

【中文标题】在 Swift 测试驱动开发中对 @ObservableObject 进行单元测试【英文标题】:Unit testing an @ObservableObject in Swift Test Driven Development 【发布时间】:2020-06-02 14:40:21 【问题描述】:

我正在尝试学习如何使用带有 TDD 的 MVVM 架构来解决一些无法在 SwiftUI 中对视图进行单元测试的问题。

我有一个带日期的 Alarm 结构:

import Foundation

struct Alarm 
    var time: Date

我有一个基本的

class AlarmPickerViewModel: ObservableObject 
    @Published var alarm: Alarm

    init(alarm: Alarm) 
        self.alarm = alarm
    


如果AlarmPickerViewModel 不是ObservableObject 的子类并且警报属性不是@Published,我正在努力研究如何编写一个失败的单元测试。

我查看了this question on the site,但它似乎对我没有帮助。

请指点一下我哪里出错了?

【问题讨论】:

“无法在 SwiftUI 中对视图进行单元测试的一些问题。”那不是真的。在 SwiftUI 中,您可以对视图进行单元测试 - 或至少在视图中测试业务逻辑,因为您可以像使用任何其他实体一样使用依赖注入。 SwiftUI 解决了 UIKit UIViewsUIViewControllers 不能依赖注入的问题。唯一不能进行单元测试的部分是 UI 的实际外观。 谢谢,知道这真的很有用。 【参考方案1】:

如果alarm 不是@Published,您可以创建一个甚至不会编译的测试,只需创建对该属性的订阅,因为您只有在它是@Published 时才能订阅它。

ObservableObject 一致性将objectWillChange Publisher 添加到您的对象中,因此要对其进行测试,您只需订阅该Publisher。如果 AlarmPickerViewModel 不是 ObservableObject,则测试甚至无法编译。

func testAlarmPickerViewModel() 
    let alarmPickerViewModel = AlarmPickerViewModel(alarm: Alarm(time: .distantFuture))

    alarmPickerViewModel.$alarm.sink(receiveValue:  print("ViewModel.alarm updated, new value: \($0)") )

    alarmPickerViewModel.objectWillChange.sink(receiveValue:  print("ViewModel updated: \($0)"))

【讨论】:

以上是关于在 Swift 测试驱动开发中对 @ObservableObject 进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 中对这个自定义 UITextField 进行单元测试?

如何在 Swift 中对私有或内部函数进行单元测试?

在 Swift 中对私有变量进行单元测试

在 Swift 中对符合协议的对象和变量进行单元测试

在 Swift 中对 Optional 值进行测试后解包时出错

如何在 Swift 中对字体进行样式化?