【问题标题】:Unit testing in SwiftUISwiftUI 中的单元测试
【发布时间】:2020-02-02 21:24:12
【问题描述】:

我正在尝试为 SwiftUI 视图编写单元测试,但在网上找到了零资源来了解如何去做。

我的观点如下

struct Page: View {
@EnvironmentObject var service: Service

var body: some View {
    NavigationView {
        ScrollView(.vertical) {
            VStack {
                Text("Some text"))
                    .font(.body)
                    .navigationBarTitle(Text("Title")))

                Spacer(minLength: 100)
            }
        }
   }
}
}

我开始写这样的测试

func testPage() {
    let page = Page().environmentObject(Service())
    let body = page.body
    XCTAssertNotNil(body, "Did not find body")
}

但是我如何获得身体内部的视图呢?我如何测试它们的属性?任何帮助表示赞赏。

更新: 事实上,即使这样也行不通。我收到以下运行时异常

Thread 1: Fatal error: body() should not be called on  ModifiedContent<Page,_EnvironmentKeyWritingModifier<Optional<Service>>>.

【问题讨论】:

  • 我真的不认为 SwiftUI 被设计为像那样进行单元测试。我会使用 UI 测试来测试 UI。
  • 在测试 UI 时,e2e/集成几乎总是优先于单元测试。当您尝试编写单元测试时,您实际上最终会测试 UI 库本身,或者您最终会在测试中复制实际代码。我的东西是可测试的,它通常可以从 UI 中移除到业务层并单独测试。 Swift UI 定义了布局。尝试对 Swift UI 进行单元测试就像尝试对 xib 或 CSS 文件进行单元测试。您可以做的最好的 uni 测试是快照测试。
  • 快照非常适合布局,但 SwiftUI 是布局 + 行为。

标签: swift swiftui xctest


【解决方案1】:

更新:让我们都尝试使用 nalexn 的 ViewInspector 库!

原回复:

直到苹果

a) 在 SwiftUI 中设计可测试性,并且

b) 向我们展示了这种可测试性,

我们搞砸了,将不得不使用 UI 测试来代替单元测试……完全颠倒了测试金字塔。

【讨论】:

    【解决方案2】:

    有一个专门用于 SwiftUI 视图的运行时检查和单元测试的框架:ViewInspector

    您可以提取自定义视图以验证内部状态、触发 UI 输入副作用、读取格式化文本值、确保应用正确的文本样式等等:

    // Side effect from tapping on a button
    try sut.inspect().find(button: "Close").tap()
    let viewModel = try sut.inspect().view(CustomView.self).actualView().viewModel
    XCTAssertFalse(viewModel.isDialogPresented)
    
    // Testing localization + formatting
    let sut = Text("Completed by \(72.51, specifier: "%.1f")%")
    let string = try sut.inspect().text().string(locale: Locale(identifier: "es"))
    XCTAssertEqual(string, "Completado por 72,5%")
    

    您的视图测试可能如下所示:

    func testPage() throws {
       let page = Page().environmentObject(Service())
       let string = try page.inspect().navigationView().scrollView().vStack().text(0).string()
       XCTAssertEqual(string, "Some text")
    }
    

    【讨论】:

    • 这个测试有什么目的?检查视图中的文本是否与字符串匹配似乎没用,听起来像单元测试是不好的做法,而是在这里使用 UI 测试。正如你...测试用户界面。为您的业务逻辑/控制器保存单元测试?
    • @Jerland2 此测试旨在表明 SwiftUI 不是黑匣子。 SwiftUI 视图可以根据业务逻辑更改的状态更改其内容的场景很多,有时检查文本的字符串非常有意义。
    • 这不是正确的答案。 @nalexn 我已经看到这样的框架来来去去很多年了,它们永远不会持续下去。然后采用它们的人最终错误地构建了他们的软件。您不应该检查 UI 中的任何逻辑。反之亦然。你应该有一个支持将你的逻辑从你的 UI 中分离出来的架构。然后你对它进行单元测试。单元测试最好的部分是它应该非常快。如果人们必须下载您的框架,然后运行 ​​UI 测试来测试应用程序,那么这将大大减慢开发速度。
    • @iOSDev9381 这个库不鼓励在 UI 中编写业务逻辑。您可以验证字符串的格式和本地化是否正确,没有一个标签缺少样式,以及许多其他与 UI 相关的“逻辑”,否则无论您如何构建您的应用程序都无法进行单元测试。您对速度的假设是错误的 - 库的整个测试套件(它是 800 个 UI 测试)运行时间不到 1.5 秒,与 UIKit 中的 UI 测试相比,这是一种完全不同的体验。
    猜你喜欢
    • 2022-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-13
    • 2013-02-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多