【问题标题】:How to delete/reset an app from iOS 13 with XCTest?如何使用 XCTest 从 iOS 13 删除/重置应用程序?
【发布时间】:2020-02-18 21:43:25
【问题描述】:

最近我开始使用 XCTest 测试一个 iOS 应用,但我发现了一些困难,主要困难是删除或重置每个测试类中的应用内容。

我目前正在使用 XCode 11 并尝试从 iOS 13 中为每个测试类删除/重置应用程序,我已经尝试过:

  • 通过跳板删除应用
  • 前往应用设置删除应用

这一步在我的测试中非常重要,因为在每个测试中我都需要创建一个配置文件并登录,所以在下一个测试中我需要从头开始安装应用程序

【问题讨论】:

    标签: xcode xctest ios13 xcode11 xcuitest


    【解决方案1】:

    iOS 14 及更低版本

    func deleteMyApp() {
    XCUIApplication().terminate()
    
    let bundleDisplayName = "App Name"
    
    XCUIDevice.shared.press(.home)
    
    let icon = springboard.icons[bundleDisplayName]
    
    if icon.waitForExistence(timeout: 5) {
        
        XCUIDevice.shared.press(.home)
    
        
        let value = springboard.pageIndicators.element(boundBy: 0).value as? String
        
        let f = value!.last?.wholeNumberValue
        for _ in (1...f!){
            if(icon.isHittable){
                break
            }
            else{
                springboard.swipeLeft()
            }
        }
    
    
        let systemVersion = UIDevice.current.systemVersion.prefix(2)
    
        switch systemVersion {
        case "13":
            icon.press(forDuration: 1)
    
            let rrd = springboard.buttons["Delete App"]
            XCTAssert(rrd.waitForExistence(timeout: 5))
            rrd.tap()
            let rrd2 = springboard.buttons["Delete"]
            XCTAssert(rrd2.waitForExistence(timeout: 5))
            rrd2.tap()
            
        case "14":
            icon.press(forDuration: 1)
    
            let rrd = springboard.buttons["Remove App"]
            XCTAssert(rrd.waitForExistence(timeout: 5))
            rrd.tap()
            let rrd2 = springboard.buttons["Delete App"]
            XCTAssert(rrd2.waitForExistence(timeout: 5))
            rrd2.tap()
            let rrd3 = springboard.buttons["Delete"]
            XCTAssert(rrd3.waitForExistence(timeout: 5))
            rrd3.tap()
            
        default:
            XCTFail("Did not handle")
        }
       
    }}
    

    【讨论】:

      【解决方案2】:

      iOS 14

      iOS 14 的工作解决方案

      import XCTest
      
      let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
      
      func deleteMyApp() {
          XCUIApplication().terminate()
      
          let bundleDisplayName = "MyApp"
      
          let icon = springboard.icons[bundleDisplayName]
          if icon.exists {
              icon.press(forDuration: 1)
      
              let buttonRemoveApp = springboard.buttons["Remove App"]
              if buttonRemoveApp.waitForExistence(timeout: 5) {
                  buttonRemoveApp.tap()
              } else {
                  XCTFail("Button \"Remove App\" not found")
              }
      
              let buttonDeleteApp = springboard.alerts.buttons["Delete App"]
              if buttonDeleteApp.waitForExistence(timeout: 5) {
                  buttonDeleteApp.tap()
              }
              else {
                  XCTFail("Button \"Delete App\" not found")
              }
      
              let buttonDelete = springboard.alerts.buttons["Delete"]
              if buttonDelete.waitForExistence(timeout: 5) {
                  buttonDelete.tap()
              }
              else {
                  XCTFail("Button \"Delete\" not found")
              }
          }
      }
      
      class HomeUITests: XCTestCase {
          override func setUpWithError() throws {
              // Put setup code here. This method is called before the invocation of each test method in the class.
      
              // In UI tests it is usually best to stop immediately when a failure occurs.
              continueAfterFailure = false
      
              // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
          }
      
          override func tearDownWithError() throws {
              // Put teardown code here. This method is called after the invocation of each test method in the class.
          }
      
          func testExample() throws {
              deleteMyApp()
      
              // UI tests must launch the application that they test.
              let app = XCUIApplication()
              app.launch()
      
              // Use recording to get started writing UI tests.
              // Use XCTAssert and related functions to verify your tests produce the correct results.
          }
      
          func testLaunchPerformance() throws {
              if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) {
                  // This measures how long it takes to launch your application.
                  measure(metrics: [XCTApplicationLaunchMetric()]) {
                      XCUIApplication().launch()
                  }
              }
          }
      }
      

      【讨论】:

        【解决方案3】:

        这是适用于 iOS 14 的快速而肮脏的解决方案:

        let appName = "You app name as it appears on the home screen"
        
        // Put the app in the background
        XCUIDevice.shared.press(XCUIDevice.Button.home)
        
        let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
        if springboard.icons[appName].waitForExistence(timeout: 5) {
            springboard.icons[appName].press(forDuration: 1.5);
        }
        
        if springboard.collectionViews.buttons["Remove App"].waitForExistence(timeout: 5) {
            springboard.collectionViews.buttons["Remove App"].tap()
        }
        
        if springboard.alerts["Remove “\(appName)”?"].scrollViews.otherElements.buttons["Delete App"].waitForExistence(timeout: 5) {
            springboard.alerts["Remove “\(appName)”?"].scrollViews.otherElements.buttons["Delete App"].tap()
        }
        
        if springboard.alerts["Delete “\(appName)”?"].scrollViews.otherElements.buttons["Delete"].waitForExistence(timeout: 5) {
            springboard.alerts["Delete “\(appName)”?"].scrollViews.otherElements.buttons["Delete"].tap()
        }
        

        【讨论】:

        • 按home键后,设备进入第一屏。但是,测试应用程序在第二个屏幕上,springboard.icons[appName] 将不可点击,这意味着无法按下。
        【解决方案4】:

        更新 Roman 的答案以在 iPad 上支持 iOS 13。

        通过插入otherElements["Home screen icons"],代码在iPhone和iPad上都可以使用。

        class Springboard {
        
            static let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
        
            class func deleteMyApp() {
                XCUIApplication().terminate()
        
                 // Insert otherElements["Home screen icons"] here
                let icon = springboard.otherElements["Home screen icons"].icons["Workoutimer"]
                if icon.exists {
                    let iconFrame = icon.frame
                    let springboardFrame = springboard.frame
                    icon.press(forDuration: 5)
        
                    // Tap the little "X" button at approximately where it is. The X is not exposed directly
                    springboard.coordinate(withNormalizedOffset: CGVector(dx: (iconFrame.minX + 3) / springboardFrame.maxX, dy: (iconFrame.minY + 3) / springboardFrame.maxY)).tap()
        
                    springboard.alerts.buttons["Delete"].tap()
                    
                    XCUIDevice.shared.press(XCUIDevice.Button.home)
                }
            }
         }
        

        杂项。

        在 iPad 上,“最近启动的应用程序”将添加到 Dock 的右侧。如果您仅按标识符搜索图标,这种 iPad 特定行为会导致 XCUITest 找到两个元素。

        Your app will be added here, too.

        要处理这个问题,请指定otherElements["Home screen icons"],它会排除“Dock”的元素。

        【讨论】:

          【解决方案5】:
          enum Springboard {
          
              static let springboardApp = XCUIApplication(bundleIdentifier: "com.apple.springboard")
              static let appName = "appName"
          
              static func deleteApp() {
                  XCUIApplication().terminate()
          
                  let icon = springboardApp.icons[appName]
                  if icon.exists {
                      icon.press(forDuration: 3)
                      icon.buttons["DeleteButton"].tap()
          
                      springboardApp.alerts.buttons["Delete"].tap()
                  }
              }
           }
          

          【讨论】:

            【解决方案6】:

            尝试比以前的 iOS 版本长按应用图标。

                let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
            
                func deleteMyApp() {
                    XCUIApplication().terminate()
            
                    let icon = springboard.icons["YourAppName"]
                    if icon.exists {
                        let iconFrame = icon.frame
                        let springboardFrame = springboard.frame
                        icon.press(forDuration: 5)
            
                        // Tap the little "X" button at approximately where it is. The X is not exposed directly
                        springboard.coordinate(withNormalizedOffset: CGVector(dx: (iconFrame.minX + 3) / springboardFrame.maxX, dy: (iconFrame.minY + 3) / springboardFrame.maxY)).tap()
            
                        springboard.alerts.buttons["Delete"].tap()
                    }
                }
            

            【讨论】:

            • 这适用于所有 iOS 版本。谢谢你:)
            • 很高兴它对您有所帮助。祝你好运!
            • 应用图标不在首屏,好像需要先向左滑动?
            猜你喜欢
            • 2016-11-24
            • 2022-08-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-07-30
            • 1970-01-01
            • 2020-02-29
            相关资源
            最近更新 更多