【问题标题】:Accessing class instance in XCTest using SwiftUI and @EnvironmentObject使用 SwiftUI 和 @EnvironmentObject 访问 XCTest 中的类实例
【发布时间】:2020-07-31 20:28:32
【问题描述】:

我有一个 SwiftUI 视图层次结构,其中包含一个使用 .environment() 注入的自定义类的实例,类似于以下内容:

struct ContentView: View {

  // Pointer to the AppStateController passed in .environment()
  @EnvironmentObject var appStateController: AppStateController

  var body: some View {
    VStack(spacing: 0) {
      TitleView()
        .modifier(TitleStyle())
        .environmentObject(appStateController)
      Spacer()
    }
  }

}


struct TitleView: View {

  @EnvironmentObject var appStateController: AppStateController

  var body: some View {

    Button(action: {
      self.appStateController.isPlaying.toggle()
    }, label: {
      if self.appStateController.isPlaying {
        Image(systemName: "stop.circle")
          .opacity(self.appStateController.isPlayable ? 1.0 : 0.5)
          .accessibility(label: Text("stop"))
      }
      else {
        Image(systemName: "play.circle")
          .opacity(self.appStateController.isPlayable ? 1.0 : 0.5)
          .accessibility(label: Text("play"))
      }
    })
  }

}

在 TitleView 上有一堆按钮,它们的动作会改变 appStateController 中的 @Published 值。这些按钮在被点击时也会改变它们的标签(图标)。

我刚刚开始进行 UI 单元测试,我已经完成了测试按钮点击更改图标(通过搜索按钮并检查其可访问性标签)的工作,但我也想通过检查 appStateController.isPlaying 布尔值来断言该操作实际上做了某事 - 有效地测试我的操作:{} 闭包是否符合我的需要。

我似乎找不到任何文档告诉我如何通过视图层次结构找到注入的 appStateController 的引用并检查其中的属性。这可能吗?如果可以,有谁知道我在哪里可以找到一些关于这样做的文档/博客文章?

【问题讨论】:

    标签: swift swiftui xctest xctestcase


    【解决方案1】:

    在 UI 测试中,您测试的是 UI 流程,而不是内部引擎状态,因此您可以验证 UI 是否代表正确的状态(即引擎正确完成并且 UI 相应更新)。为此,它需要识别所需的 UI 元素,然后检查运行时是否存在所需的元素。

    这是可能的方法。使用 Xcode 11.4 测试。

    1) 在代码中添加可访问性标识符

          if self.appStateController.isPlaying {
            Image(systemName: "stop.circle")
              .opacity(self.appStateController.isPlayable ? 1.0 : 0.5)
              .accessibility(identifier: "playing")       // identify state !!
              .accessibility(label: Text("stop"))
          }
          else {
            Image(systemName: "play.circle")
              .opacity(self.appStateController.isPlayable ? 1.0 : 0.5)
              .accessibility(identifier: "idle")
              .accessibility(label: Text("play"))        // identify state !!
          }
    

    2) 在 XC 测试中

        func testPlaying() throws {
            // UI tests must launch the application that they test.
            let app = XCUIApplication()
            app.launch()
    
            // UI manipulations to activate playback
    
            XCTAssertTrue(app.images["playing"].exists)
        }
    

    【讨论】:

    • 我想,从逻辑上思考,这确实测试了 isPlaying 布尔值,不是吗。如果动作闭包没有更新布尔值,层次结构中就不存在播放/空闲图像?不过看起来有点笨拙——如果我有一个图标没有更新的用例会发生什么?真的不能直接检查布尔值吗?
    • 我想要测试它的部分理由是我在 Xcode 11.4 中遇到了一个错误,其中 didSet 不会因为 @Published 属性而被触发。它在 11.3.1 中运行良好。这就是促使我首先研究编写单元测试的原因。通过直接实例化类并直接触发切换而不对 UI 进行操作,我会更好地对这些进行单元测试吗?
    • @Chris,如果你想直接测试引擎级别,你应该只使用普通的单元测试方法,而不是 UI 单元测试。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多