如何对@ViewBuilder 函数进行单元测试?

How to unit test an @ViewBuilder function?

示例函数:

@ViewBuilder func returnView() -> some View {
        if thisIsTrue == true {
            SomeView()
        } else {
            AnotherView()
        }
    }

我试过这样测试:

let testView = sut.returnView()
XCTAssert(testView is SomeView)

当只有一种可能的视图类型时通过,但一旦有选择就会失败。

关于如何对这个函数的输出进行单元测试有什么建议吗?

不透明 return 类型 some View 意味着此函数始终 return 在函数的所有路径上恰好是一种类型,并且该类型符合 View,所以虽然看起来您正在 return 处理两种不同的事物,但 ViewBuilder 实际上将其折叠为一种类型,该类型相对于真正的 return 类型是通用的。如果你想知道真正的不透明类型是什么,你可以让编译器告诉你。例如这里是一个游乐场。请注意,此解决方案很脆弱,因为更改函数的实现很可能会更改 return 类型。

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()
   }
}

我希望这对其他人有帮助。