有没有办法在Swift XCTest UI中的两次测试之间重置应用程序?


74

XCTest中是否存在API调用,我可以将其放入setUP()或tearDown()中以在两次测试之间重置应用程序?我查看了XCUIApplication的点语法,只看到了.launch()

或者有没有办法在Swift中调用Shell脚本?然后,我可以在测试方法之间调用xcrun来重置模拟器。


1
有趣的是,当我写这个问题时,我找不到这个问题。我将糟糕的查询结果归咎于SO。任何人,随时删除此“重复项”,我不久前使用具有快速通道/gitlab-ci.yml文件的优雅解决方案解决了该问题。
激光鹰

2
您如何使用gitlab-ci.yml文件解决该问题?你能分享点什么吗?
Dhruv

Answers:


83

您可以添加“运行脚本”阶段来在测试目标中构建阶段,以在针对应用运行单元测试之前卸载应用程序,但是不幸的是这不在测试案例之间

/usr/bin/xcrun simctl uninstall booted com.mycompany.bundleId

更新资料


在两次测试之间,您可以在tearDown阶段通过Springboard删除该应用程序。虽然,这确实需要使用XCTest的专用标头。(可从Facebook的WebDriverAgent此处获得标头转储。)

这是Springboard类中的一些示例代码,可通过点击并按住从Springboard中删除应用程序:

斯威夫特4:

import XCTest

class Springboard {

    static let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")

    /**
     Terminate and delete the app via springboard
     */
    class func deleteMyApp() {
        XCUIApplication().terminate()

         // Force delete the app from the springboard
        let icon = springboard.icons["Citizen"]
        if icon.exists {
            let iconFrame = icon.frame
            let springboardFrame = springboard.frame
            icon.press(forDuration: 1.3)

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

迅捷3-:

import XCTest

class Springboard {

    static let springboard = XCUIApplication(privateWithPath: nil, bundleID: "com.apple.springboard")

    /**
     Terminate and delete the app via springboard
     */
    class func deleteMyApp() {
        XCUIApplication().terminate()

        // Resolve the query for the springboard rather than launching it
        springboard.resolve()

        // Force delete the app from the springboard
        let icon = springboard.icons["MyAppName"]
        if icon.exists {
            let iconFrame = icon.frame
            let springboardFrame = springboard.frame
            icon.pressForDuration(1.3)

            // Tap the little "X" button at approximately where it is. The X is not exposed directly
            springboard.coordinateWithNormalizedOffset(CGVectorMake((iconFrame.minX + 3) / springboardFrame.maxX, (iconFrame.minY + 3) / springboardFrame.maxY)).tap()

            springboard.alerts.buttons["Delete"].tap()
        }
    }
 }

接着:

override func tearDown() {
    Springboard.deleteMyApp()
    super.tearDown()
}

专用标头已导入到Swift桥接标头中。您需要导入:

// Private headers from XCTest
#import "XCUIApplication.h"
#import "XCUIElement.h"

注意:从Xcode 10开始,XCUIApplication(bundleIdentifier:)Apple现在公开了它,并且不再需要private标头。


2
好答案!有没有更聪明的方式来获取“ MyAppName”?我尝试使用NSBundle-bundleWithIdentifier/Path,但是测试应用程序没有对应用程序包的引用。我的项目有许多目标,每个目标都有不同的名称,并且我希望能够在所有目标上使用Springboard类。
阿维(Avi)

1
测试开始后可以完成吗?如果可以,我该如何重新安装该应用程序?
Guig

3
小的“ x”按钮的可访问性标识符为“ DeleteButton”,可以通过icon.buttons["DeleteButton"].tap()在长按后运行而不是使用来点按CGVector
pmick

6
由于iOS的13.4的,我现在得到一个错误,当我打电话app.launch()Springboard.deleteMyApp()The request was denied by service delegate (SBMainWorkspace) for reason: NotFound ("Application "com.serpentisei.studyjapanese" is unknown to FrontBoard").
克里斯Vasselli

3
不论模拟器的iOS版本如何,上述错误似乎都是在Xcode 11.4中引入的。每当您启动应用程序,使用上述技术删除应用程序,然后尝试再次启动它时,它就会发生(即使这是在单独的测试中进行的)。我已经提交了FB7666257。
克里斯·瓦塞利

40

目前,Xcode和Simulator中的公共API并未显示可从该模拟器的“重置内容和设置”setUp()及其tearDown() XCText子类中调用的任何方法。

还有其他使用公共API的方法:

  1. 应用代码。添加一些myResetApplication()应用程序代码以使应用程序处于已知状态。但是,设备(模拟器)状态控制受到应用程序沙箱的限制……这在应用程序外部没有太大帮助。这种方法可以清除应用程序可控的持久性。

  2. Shell脚本。从shell脚本运行测试。在每次测试运行之间使用xcrun simctl erase allxcrun simctl uninstall <device> <app identifier>类似方法重置模拟器(或卸载应用程序)请参见StackOverflow:“如何从命令行重置iOS模拟器?”

xcrun simctl --help
# Uninstall a single application
xcrun simctl uninstall --help  
xcrun simctl uninstall <device> <app identifier>

# Erase a device's contents and settings.
xcrun simctl erase <device>
xcrun simctl erase all      # all existing devices

# Grant, revoke, or reset privacy and permissions
simctl privacy <device> <action> <service> [<bundle identifier>]
  1. Xcode Schema脚本操作。向Xcode Scheme部分(例如Test或Build部分)添加xcrun simctl erase all(或xcrun simctl erase <DEVICE_UUID>)或类似命令。选择产品>方案>编辑方案...菜单。展开方案测试部分。在“测试”部分下选择“预操作”。单击(+)添加“新建运行脚本操作”。xcrun simctl erase all可以直接键入命令,而无需任何外部脚本。

调用选项1.重置应用程序的应用程序代码

A.应用程序界面[UI测试]提供一个重置按钮或其他UI动作来重置应用程序。UI元素可通过行使XCUIApplicationXCTest例程setUp()tearDown()testSomething()

B.启动参数[UI测试]如Victor Ronin所述,可以从测试中传递参数setUp()

class AppResetUITests: XCTestCase {

  override func setUp() {
    // ...
    let app = XCUIApplication()
    app.launchArguments = ["MY_UI_TEST_MODE"]
    app.launch()

...由AppDelegate...接收

class AppDelegate: UIResponder, UIApplicationDelegate {

  func application( …didFinishLaunchingWithOptions… ) -> Bool {
    // ...
    let args = NSProcessInfo.processInfo().arguments
    if args.contains("MY_UI_TEST_MODE") {
      myResetApplication()
    }

C. Xcode方案参数[UI测试,单元测试] 选择产品>方案>编辑方案…菜单。展开“方案运行”部分。(+)添加一些参数,例如MY_UI_TEST_MODE。该参数将在中可用NSProcessInfo.processInfo()

// ... in application
let args = NSProcessInfo.processInfo().arguments
if args.contains("MY_UI_TEST_MODE") {
    myResetApplication()
}

Z.直接通话[单元测试]单元测试包被注入到正在运行的应用程序中,并且可以直接myResetApplication()在应用程序中调用某些例程。注意:加载主屏幕后,将运行默认的单元测试。请参阅测试加载顺序。但是,UI测试包作为被测试应用程序外部的进程运行。因此,在单元测试中有效的方法在UI测试中给出了链接错误。

class AppResetUnitTests: XCTestCase {

  override func setUp() {
    // ... Unit Test: runs.  UI Test: link error.
    myResetApplication() // visible code implemented in application

xcrun simctl erase all是一个很好的建议-谢谢!
条例草案

除了第三种解决方案,您还可以在测试目标构建阶段中轻轻卸载应用程序。看我的答案。
vmeyer

15

更新为Swift 3.1 / Xcode 8.3

在测试目标中创建桥接头:

#import <XCTest/XCUIApplication.h>
#import <XCTest/XCUIElement.h>

@interface XCUIApplication (Private)
- (id)initPrivateWithPath:(NSString *)path bundleID:(NSString *)bundleID;
- (void)resolve;
@end

更新了Springboard类

class Springboard {
   static let springboard = XCUIApplication(privateWithPath: nil, bundleID: "com.apple.springboard")!
   static let settings = XCUIApplication(privateWithPath: nil, bundleID: "com.apple.Preferences")!

/**
Terminate and delete the app via springboard
*/

class func deleteMyApp() {
   XCUIApplication().terminate()

// Resolve the query for the springboard rather than launching it

   springboard.resolve()

// Force delete the app from the springboard
   let icon = springboard.icons["{MyAppName}"] /// change to correct app name
   if icon.exists {
     let iconFrame = icon.frame
     let springboardFrame = springboard.frame
     icon.press(forDuration: 1.3)

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

     // Press home once make the icons stop wiggling

     XCUIDevice.shared().press(.home)
     // Press home again to go to the first page of the springboard
     XCUIDevice.shared().press(.home)
     // Wait some time for the animation end
     Thread.sleep(forTimeInterval: 0.5)

      let settingsIcon = springboard.icons["Settings"]
      if settingsIcon.exists {
       settingsIcon.tap()
       settings.tables.staticTexts["General"].tap()
       settings.tables.staticTexts["Reset"].tap()
       settings.tables.staticTexts["Reset Location & Privacy"].tap()
       settings.buttons["Reset Warnings"].tap()
       settings.terminate()
      }
     }
    }
   }

完美的作品!
Wilmar

非常好 !完美工作
Sn0wfreeze 17-4-26

1
在设备上运行此程序时,有时会收到“信任此计算机?”的消息。警报,这会阻止我的应用启动。
kjam

在最新的Xcode / XCtest中仍然可以使用吗?如果是这样,您如何/在何处启动deleteMyApp()?
BadmintonCat

...有效!惊人!
BadmintonCat

11

您可以要求您的应用自行“清理”

  • XCUIApplication.launchArguments用来设置一些标志

  • 在AppDelegate中检查

    如果NSProcessInfo.processInfo()。arguments.contains(“ YOUR_FLAG_NAME_HERE”){//在这里进行清理}


这是我了解launchArgruments方法的重要一步。感谢您的见解。它导致我进入nshipster.com/launch-arguments-and-environment-variables 请在这里打扰我。如果我编辑方案并创建启动参数,那么在哪里以及如何设置新创建的参数的细节?我看到了如何将其作为令牌传递给测试,但是就像我的情况一样,我想运行一个重置模拟器状态的脚本。您能否对创建实际参数进行更详细的说明?
激光鹰

@jermobileqa首先,不需要道歉。我和你差不多。我从今天开始真正使用新的UI测试。我一直在寻找如何完全解决这个问题。我目前在我的测试的setUp方法中设置XCUIApplication.launchArguments,并在func应用程序的AppDelegate中对其进行检查。我没有修改架构。结果,我可以使用Command + U从XCode运行测试,它将使用此参数,并且我的应用程序将清除所有持久化的内容。
维克多·罗宁

如何重置应用权限?
LetynSOFT '02

9

我使用了@ ODM 答案,但对其进行了修改,使其可用于Swift 4。我已经在iPhone 7模拟器和iPad Air模拟器上以纵向方向对其进行了测试,它适用于我的应用程序。

斯威夫特4

import XCTest
import Foundation

class Springboard {

let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
let settings = XCUIApplication(bundleIdentifier: "com.apple.Preferences")


/**
 Terminate and delete the app via springboard
 */
func deleteMyApp() {
    XCUIApplication().terminate()

    // Resolve the query for the springboard rather than launching it
    springboard.activate()

    // Rotate back to Portrait, just to ensure repeatability here
    XCUIDevice.shared.orientation = UIDeviceOrientation.portrait
    // Sleep to let the device finish its rotation animation, if it needed rotating
    sleep(2)

    // Force delete the app from the springboard
    // Handle iOS 11 iPad 'duplication' of icons (one nested under "Home screen icons" and the other nested under "Multitasking Dock"
    let icon = springboard.otherElements["Home screen icons"].scrollViews.otherElements.icons["YourAppName"]
    if icon.exists {
        let iconFrame = icon.frame
        let springboardFrame = springboard.frame
        icon.press(forDuration: 2.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()
        // Wait some time for the animation end
        Thread.sleep(forTimeInterval: 0.5)

        //springboard.alerts.buttons["Delete"].firstMatch.tap()
        springboard.buttons["Delete"].firstMatch.tap()

        // Press home once make the icons stop wiggling
        XCUIDevice.shared.press(.home)
        // Press home again to go to the first page of the springboard
        XCUIDevice.shared.press(.home)
        // Wait some time for the animation end
        Thread.sleep(forTimeInterval: 0.5)

        // Handle iOS 11 iPad 'duplication' of icons (one nested under "Home screen icons" and the other nested under "Multitasking Dock"
        let settingsIcon = springboard.otherElements["Home screen icons"].scrollViews.otherElements.icons["Settings"]
        if settingsIcon.exists {
            settingsIcon.tap()
            settings.tables.staticTexts["General"].tap()
            settings.tables.staticTexts["Reset"].tap()
            settings.tables.staticTexts["Reset Location & Privacy"].tap()
            // Handle iOS 11 iPad difference in error button text
            if UIDevice.current.userInterfaceIdiom == .pad {
                settings.buttons["Reset"].tap()
            }
            else {
                settings.buttons["Reset Warnings"].tap()
            }
            settings.terminate()
        }
    }
  }
}

3
我不得不进一步更改此设置,因为由于缩放比例更改,它无法在“ Plus”型号手机上使用。如果将常量“ 3”替换为“ 3 * UIScreen.main.scale”,则它将正常工作。
SlashDevSlashGnoll

我似乎无法让我的iPad按下x按钮。有人在iPad上有运气吗?
bj97301 '18

如下面的答案所示,我能够解决此问题。
bj97301 '18

9

iOS 13.2解决方案

final class Springboard {

    private static var springboardApp = XCUIApplication(bundleIdentifier: "com.apple.springboard")

    class func deleteApp(name: String) {
        XCUIApplication().terminate()

        springboardApp.activate()

        sleep(1)

        let appIcon = springboardApp.icons.matching(identifier: name).firstMatch
        appIcon.press(forDuration: 1.3)

        sleep(1)

        springboardApp.buttons["Delete App"].tap()

        let deleteButton = springboardApp.alerts.buttons["Delete"].firstMatch
        if deleteButton.waitForExistence(timeout: 5) {
            deleteButton.tap()
        }
    }
}

8

我使用@Chase Holland答案,并按照相同的方法使用“设置”应用程序重置内容和设置来更新Springboard类。当您需要重置权限对话框时,这很有用。

import XCTest

class Springboard {
    static let springboard = XCUIApplication(privateWithPath: nil, bundleID: "com.apple.springboard")
    static let settings = XCUIApplication(privateWithPath: nil, bundleID: "com.apple.Preferences")

    /**
     Terminate and delete the app via springboard
     */
    class func deleteMyApp() {
        XCUIApplication().terminate()

        // Resolve the query for the springboard rather than launching it
        springboard.resolve()

        // Force delete the app from the springboard
        let icon = springboard.icons["MyAppName"]
        if icon.exists {
            let iconFrame = icon.frame
            let springboardFrame = springboard.frame
            icon.pressForDuration(1.3)

            // Tap the little "X" button at approximately where it is. The X is not exposed directly
            springboard.coordinateWithNormalizedOffset(CGVectorMake((iconFrame.minX + 3) / springboardFrame.maxX, (iconFrame.minY + 3) / springboardFrame.maxY)).tap()

            springboard.alerts.buttons["Delete"].tap()

            // Press home once make the icons stop wiggling
            XCUIDevice.sharedDevice().pressButton(.Home)
            // Press home again to go to the first page of the springboard
            XCUIDevice.sharedDevice().pressButton(.Home)
            // Wait some time for the animation end
            NSThread.sleepForTimeInterval(0.5)

            let settingsIcon = springboard.icons["Settings"]
            if settingsIcon.exists {
                settingsIcon.tap()
                settings.tables.staticTexts["General"].tap()
                settings.tables.staticTexts["Reset"].tap()
                settings.tables.staticTexts["Reset Location & Privacy"].tap()
                settings.buttons["Reset Warnings"].tap()
                settings.terminate()
            }
        }
    }
}

XCUIApplication(privateWithPath: …)不会在Swift 3中公开吗?
成功

1
@buildsucceed,您需要创建一个桥接头并导入私有头。检查我的答案是否正确实施。
JustinM '17

6

我看到了很多有关卸载您的应用程序setUptearDown测试的答案。

但是,您可以在测试之前通过在测试目标中添加运行脚本阶段来轻松卸载应用程序。

为此:

  1. 选择应用程序的Xcode项目
  2. 选择测试目标
  3. 选择“构建阶段”
  4. 点击“ +”和“新运行脚本阶段”

然后,用# Type a script or drag a script file from your workspace to insert its path.以下命令替换占位符:

xcrun simctl boot ${TARGET_DEVICE_IDENTIFIER}
xcrun simctl uninstall ${TARGET_DEVICE_IDENTIFIER} YOUR_APP_BUNDLE

知道如何获取测试将在其中运行的克隆的ID吗?仅在其他克隆仍在运行测试时才希望删除该克隆
Alexandre G

嗨@AlexandreG,您在说什么克隆?您是在谈论模拟器吗?
vmeyer

是的,使用Xcode 10+并行测试时,将在具有自己ID的模拟器克隆上运行测试。在他人的帮助下,我找到了如何擦除它们stackoverflow.com/questions/52660037/…但不知道如何在测试前识别要擦除的那个
Alexandre G

我不知道如何获取这些克隆ID,但是Xcode应该创建目标模拟器的克隆,因此,如果您在目标模拟器上删除应用程序,则也应该在克隆上将其删除。
vmeyer

1
此外,如果您确实要管理克隆,则可以使用CLI使用以下命令创建自己的模拟器,xcrun simctl create然后在这些模拟器上启动测试,并将多个目标设置为xcodebuild testcommand。如果它不工作,尝试选择-only-testing:xcodebuild test-without-building分离UITests自己。
vmeyer

6

从Xcode 11.4开始,如果您只想重置权限,则可以resetAuthorizationStatus(for:)在的实例上使用XCUIApplication,请参阅 https://developer.apple.com/documentation/xctest/xcuiapplication/3526066-resetauthorizationstatusforresou

您也可以simctl根据需要使用Xcode 11.4发行说明中引用的内容:

simctl现在支持修改隐私权限。您可以修改隐私权限以创建已知状态以进行测试。例如,要允许示例应用程序访问照片库而没有任何提示:
xcrun simctl privacy <device> grant photos com.example.app

要将所有权限重置为默认值,就像以前从未安装过该应用程序一样:
xcrun simctl privacy <device> reset all com.example.app


4
令人讨厌的是,这似乎不适用于通知权限。
bencallis '20

@bencallis嘿,您是否找到任何方法可以在不删除应用程序的情况下重置通知权限?
DmitrievichR

恼人的不是!
Bencallis

4

对于iOS 11 sims up,我进行了非常细微的修改,以点按“ x”图标,然后按@Code Monkey建议的修复方式点按。Fix在10.3和11.2手机SIM卡上均可正常运行。作为记录,我使用的是swift3。我想通过那里的一些代码来复制和粘贴以找到更容易的修复程序。:)

import XCTest

class Springboard {

    static let springboard = XCUIApplication(privateWithPath: nil, bundleID: "com.apple.springboard")

    class func deleteMyApp() {
        XCUIApplication().terminate()

        // Resolve the query for the springboard rather than launching it
        springboard!.resolve()

        // Force delete the app from the springboard
        let icon = springboard!.icons["My Test App"]
        if icon.exists {
            let iconFrame = icon.frame
            let springboardFrame = springboard!.frame
            icon.press(forDuration: 1.3)

            springboard!.coordinate(withNormalizedOffset: CGVector(dx: (iconFrame.minX + 3 * UIScreen.main.scale) / springboardFrame.maxX, dy: (iconFrame.minY + 3 * UIScreen.main.scale) / springboardFrame.maxY)).tap()

            springboard!.alerts.buttons["Delete"].tap()
        }
    }
}

3

这似乎对我在iOS 12.1和模拟器上有效

class func deleteApp(appName: String) {
    XCUIApplication().terminate()

    // Force delete the app from the springboard
    let icon = springboard.icons[appName]
    if icon.exists {
        icon.press(forDuration: 2.0)

        icon.buttons["DeleteButton"].tap()
        sleep(2)
        springboard.alerts["Delete “\(appName)”?"].buttons["Delete"].tap()
        sleep(2)

        XCUIDevice.shared.press(.home)
    }
}

3

iOS 13.1 / Swift 5.1基于UI的删除

static let springboard = XCUIApplication(privateWithPath: nil, bundleID: "com.apple.springboard")!

class func deleteApp() {
    XCUIApplication().terminate()
    XCUIDevice.shared.press(.home)
    XCUIDevice.shared.press(.home)

    let icon = springboard.icons["YourApplication"]
    if !icon.exists { return }

    springboard.swipeLeft()
    springboard.activate()
    Thread.sleep(forTimeInterval: 1.0)

    icon.press(forDuration: 1.3)
    springboard.buttons["Rearrange Apps"].eventuallyExists().tap()

    icon.buttons["DeleteButton"].eventuallyExists().tap()
    springboard.alerts.buttons["Delete"].eventuallyExists().tap()

    XCUIDevice.shared.press(.home)
    XCUIDevice.shared.press(.home)
}

3
这对您可靠吗?间歇性地为我找到“ DeleteButton”存在问题。
1919年

@bencallis一样
Ryan Maloney

你是对的,对我来说也很脆弱。我正在考虑擦除整个模拟器,直到找不到正确的方法。
Akos Komuves

我还看到错误的图标坐标。我是x:-2,y:4。发生这种情况时,deleteButton不存在。我尝试了刷新元素树,但没有帮助。
Degard

我已经更新了方法,请尝试这种方法。现在它为我工作。但是13.2即将到来,我认为这已经过时了
Akos Komuves

0

更新Craig Fishers的Swift 4答案。针对iPad在景观中进行了更新,可能仅适用于左侧景观。

导入XCTest

跳板类{

static let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")

class func deleteMyApp(name: String) {        
    // Force delete the app from the springboard
    let icon = springboard.icons[name]
    if icon.exists {
        let iconFrame = icon.frame
        let springboardFrame = springboard.frame
        icon.press(forDuration: 2.0)

        var portaitOffset = 0.0 as CGFloat
        if XCUIDevice.shared.orientation != .portrait {
            portaitOffset = iconFrame.size.width - 2 * 3 * UIScreen.main.scale
        }

        let coord = springboard.coordinate(withNormalizedOffset: CGVector(dx: (iconFrame.minX + portaitOffset + 3 * UIScreen.main.scale) / springboardFrame.maxX, dy: (iconFrame.minY + 3 * UIScreen.main.scale) / springboardFrame.maxY))
        coord.tap()

        let _ = springboard.alerts.buttons["Delete"].waitForExistence(timeout: 5)
        springboard.alerts.buttons["Delete"].tap()

        XCUIDevice.shared.press(.home)
    }
}

}


0

这是上述答案的Objective C版本,用于删除应用并重置警告(已在iOS 11和12上测试):

- (void)uninstallAppNamed:(NSString *)appName {

    [[[XCUIApplication alloc] init] terminate];

    XCUIApplication *springboard = [[XCUIApplication alloc] initWithBundleIdentifier:@"com.apple.springboard"];
    [springboard activate];
    XCUIElement *icon = springboard.otherElements[@"Home screen icons"].scrollViews.otherElements.icons[appName];

    if (icon.exists) {
        [icon pressForDuration:2.3];
        [icon.buttons[@"DeleteButton"] tap];
        sleep(2);
        [[springboard.alerts firstMatch].buttons[@"Delete"] tap];
        sleep(2);
        [[XCUIDevice sharedDevice] pressButton:XCUIDeviceButtonHome];
        sleep(2);
    }
}

..

- (void)resetWarnings {

    XCUIApplication *settings = [[XCUIApplication alloc] initWithBundleIdentifier:@"com.apple.Preferences"];
    [settings activate];
    sleep(2);
    [settings.tables.staticTexts[@"General"] tap];
    [settings.tables.staticTexts[@"Reset"] tap];
    [settings.tables.staticTexts[@"Reset Location & Privacy"] tap];

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        [settings.buttons[@"Reset"] tap];
    } else {
        [settings.buttons[@"Reset Warnings"] tap];
    }
    sleep(2);
    [settings terminate];
}

0

这适用于所有操作系统版本(iOS11、12和13)

static let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")

    func deleteApp() {
        XCUIApplication().terminate()
        springboard.activate()

        let icon = springboard.icons[appName]

        if icon.exists {
            icon.firstMatch.press(forDuration: 5)
            icon.buttons["DeleteButton"].tap()

            let deleteConfirmation = springboard.alerts["Delete “\(appName)”?"].buttons["Delete"]
            XCTAssertTrue(deleteConfirmation.waitForExistence(timeout: 5), "Delete confirmation not shown")
            deleteConfirmation.tap()
        }
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.