使用Combine在SwiftUI中模拟视图模型

3
有没有一种方法可以模拟使用SwiftUI和Combine的应用程序的视图模型?我总是找到关于模拟viewmodel使用的服务的文章,但从未模拟过viewmodel本身。
我尝试为每个viewmodel创建协议。问题是:@Published包装器无法在协议中使用。似乎没有解决方案...
谢谢您的帮助。
2个回答

3
使用协议类型,例如@ObservableObject@StateObject将不起作用。继承可能是一种解决方法(就像Jake建议的那样),或者您可以选择通用解决方案。
protocol ContentViewModel: ObservableObject {
    var message: String { get set }
}

你的视图模型将会很简单。
final class MyViewModel: ContentViewModel {
    
    @Published var message: String
    init(_ message: String = "MyViewModel") {
        self.message = message
    }
}

另一方面,如果使用有限制的通用方法,你的观点可能会更加复杂。

struct ContentView<Model>: View where Model: ContentViewModel {
    @ObservedObject
    var viewModel: Model
    
    var body: some View {
        VStack {
            Text(viewModel.message)
            Button("Change message") {
                viewModel.message = ""
            }
        }
    }
}

缺点是在使用视图时必须定义通用具体类型 --- 继承可以避免这一点。
// your mock implementation for testing
final class MockViewModel: ContentViewModel {
    @Published var message: String = "Mock View Model"
}

let sut = ContentView<MockViewModel>(viewModel: MockViewModel())

谢谢。我已经使用协议完成了这个。唯一的问题(除了复杂性)是您无法访问属性的发布者。 ViewModel模拟的想法不仅适用于测试,还适用于注入(并对预览进行模拟的ViewModel)。 - Edwin ZAP
是的,在这里不可能实现,我也想不出解决方案。你可以将协议类型定义为Publisher Published<String>.Publisher,但我认为沿着这条路走没有任何好处,只会增加复杂性。 - mgratzer
谢谢。我会接受 Swift 的限制。感谢您的建议。 - Edwin ZAP

1
如果视图模型仅是一个模型,您可能根本不需要模拟它,而应该模拟修改视图模型的内容。如果您的视图模型实际上拥有更新自身的函数和内容,则希望直接模拟它。在这种情况下,您可以使用协议来模拟视图模型。它会看起来像这样。
protocol ViewModel {
    var title: String { get set }
}

class MyViewModel: ViewModel {
    @Published var title: String = "Page title"
}

class MockViewModel: ViewModel {
    @Published var title: String = "MockPage title"
}

然而,这可能是我更喜欢继承类而不是遵循协议的情况。然后,我会为模拟覆盖类的功能。
open class ViewModel {
    @Published var title: String

    open fun getPageTitle() {
        title = "This is the page title"
    }
}

class MockViewModel: ViewModel {
    override fun getPageTitle() {
        title = "some other page title"
    }
}

无论哪种方式都可以工作。如果您的视图模型也具有功能,则继承方式在测试套件中会更少冗长。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接