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

时间:2021-01-12 18:20:41

标签: swiftui tdd viewbuilder

示例函数:

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

我尝试过这样的测试:

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

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

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

2 个答案:

答案 0 :(得分:1)

不透明的返回类型 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>

答案 1 :(得分:0)

我采用的解决方案是根本不对函数的输出进行单元测试。

我在视图模型中创建了一个枚举,其中包含映射到不同视图的案例,然后使用这种类型的计算属性将业务逻辑与视图逻辑分开。

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

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