问题描述
示例函数:
@viewbuilder func returnView() -> some View {
if thisIsTrue == true {
SomeView()
} else {
AnotherView()
}
}
我尝试过这样的测试:
let testView = sut.returnView()
XCTAssert(testView is SomeView)
当只有一种可能的视图类型时会通过,但一旦有选择就会失败。
解决方法
不透明的返回类型 some View
意味着这个函数在函数的所有路径上总是只返回一种类型,并且该类型符合 View
,所以虽然看起来你正在返回两种不同的东西ViewBuilder 实际上将它折叠成一个单一类型,该类型对于实际返回类型是通用的。如果你想知道 opaque 类型到底是什么,你可以让编译器告诉你。例如这里是一个游乐场。请注意,此解决方案很脆弱,因为更改函数的实现很可能会更改返回类型。
import SwiftUI
struct SomeView: View {
var body: some View { EmptyView() }
}
struct AnotherView: View {
var body: some View { Color.red}
}
@ViewBuilder func returnView() -> some View {
if true {
SomeView()
} else {
AnotherView()
}
}
let a = returnView()
print(type(of: a))
输出:
_ConditionalContent<SomeView,AnotherView>
,
我采用的解决方案是根本不对函数的输出进行单元测试。
我在视图模型中创建了一个枚举,其中包含映射到不同视图的案例,然后使用这种类型的计算属性将业务逻辑与视图逻辑分开。
enum ViewType {
case someView
case anotherView
}
var viewType: ViewType {
if thisIsTrue {
return .someView
} else {
return .anotherView
}
}
我可以在我的单元测试中实例化和测试它。
然后在视图本身中我创建了一个 @ViewBuilder 变量并使用 switch 语句将其映射到视图模型 viewType:
@ViewBuilder var view: some View {
switch viewModel.viewType {
case .someView:
SomeView()
case .anotherView:
AnotherView()
}
}
我希望这对其他人有帮助。