ios ui自动化测试_ui测试ios中的深层链接和通用链接

本文介绍了如何使用XCUITest进行iOS应用的UI自动化测试,特别是针对深链接和通用链接的测试。通过模拟在Safari和Messages中触发链接,然后检查应用程序是否正确响应和启动,确保它们在各种状态(如后台运行或已终止)下都能正常工作。测试涉及启动其他应用、模拟用户交互和处理不同应用状态的转换,从而全面验证深层链接和通用链接的正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ios ui自动化测试

Did you know it’s possible to terminate your app in the middle of an XCUITest and launch it again from somewhere else? Let’s see how to use this trick to test that deep links and universal links are properly launching your app when executed from Safari or iMessage.

您是否知道可以在XCUITest终止应用程序并从其他地方再次启动它? 让我们看看如何使用此技巧来测试从Safari或iMessage执行深链接和通用链接是否正确启动了您的应用程序。

It’s tricky to test iOS features because while you can write unit tests to guarantee that your abstraction of it works, you can’t really unit-test for whether iOS will correctly call what you think will be called. In the case of deep links, what iOS does differs depending on the current state of your app (closed or in the background) and which delegates you support (AppDelegates versus SceneDelegates). This commonly leads to very confusing bug reports from the point of view of the developer who isn’t aware of this fact.

测试iOS功能非常棘手,因为尽管您可以编写单元测试以确保对它的抽象进行工作,但是您无法真正对iOS是否正确调用您认为要调用的内容进行单元测试。 在深层链接的情况下,iOS的操作会因应用程序的当前状态(关闭或处于后台状态)以及您支持的代表( AppDelegatesSceneDelegates )而SceneDelegates 。 从不了解这一事实的开发人员的角度来看,这通常会导致非常令人困惑的错误报告。

But unless you’re not supporting iOS 11 in 2020 for some reason, you can perfectly test “app launch”-related features and any other AppDelegate/SceneDelegate-related feature through UI Tests. This is because it was in iOS 11 that XCUI started supporting the ability to launch and control system apps.

但是,除非您出于某种原因在2020年不支持iOS 11,否则您可以通过UI测试完美地测试与“应用程序启动”相关的功能以及任何其他与AppDelegate / SceneDelegate相关的功能。 这是因为XCUI在iOS 11中开始支持启动和控制系统应用程序的功能。

Today, we can make a test that boots Safari, types a URL, and deep-links back to our app. We can even terminate our app (which doesn’t stop the test!) to check that our app behaves correctly if it’s launched from said deep link!

今天,我们可以进行测试,以启动Safari,键入URL并深度链接回我们的应用程序。 我们甚至可以终止我们的应用程序(这不会停止测试!),以检查我们的应用程序是否从所述深层链接启动而正常运行!

UI测试深层链接(从后台应用程序) (UI Testing Deep Links (From a Backgrounded App))

To begin, let’s UI test a Safari deep link when our app is already running in the background.

首先,让我们的UI在我们的应用程序已经在后台运行时测试Safari深度链接。

Launching other apps in the middle of a UI test is similar to launching our own, with the simple difference that you pass a different bundle identifier instead. In the case of Safari, the bundle identifier is "com.apple.mobilesafari":

在UI测试过程中启动其他应用程序类似于启动我们自己的应用程序,只是区别在于您传递了不同的包标识符。 对于Safari,捆绑包标识符为"com.apple.mobilesafari"

func testDeeplinkFromSafari() {
    let app = XCUIApplication()
    app.launch()
    let safari = XCUIApplication(bundleIdentifier: "com.apple.mobilesafari")
    safari.launch()
}

If you run this, you’ll get a simple test that launches your app and switches to Safari right after.

如果运行此程序,您将获得一个简单的测试,该测试将启动您的应用程序,然后立即切换到Safari。

Now, to deep-link back to our app, we can control Safari just like we would in a regular UI test. In this case, we can grab a hold of the address bar, type our link, and press the “go” button. If everything works correctly, Safari will deep-link back to our app, allowing us to assert that the deep link logic in our app is working as expected.

现在,要深层链接回我们的应用程序,我们可以像在常规UI测试中一样控制Safari。 在这种情况下,我们可以抓住地址栏,输入链接,然后按“执行”按钮。 如果一切正常,Safari就会将其深链接回我们的应用程序,从而使我们能够断言应用程序中的深层链接逻辑正在按预期工作。

func testDeeplinkFromSafari() {
    // Launch our app
    let app = XCUIApplication()
    app.launch()
    // Launch Safari and deeplink back to our app
    openFromSafari("swiftrocks://profile")
    // Make sure Safari properly switched back to our app before asserting
    XCTAssert(app.wait(for: .runningForeground, timeout: 5))
    // Assert that the deeplink worked by checking if we're in the "Profile" screen
    XCTAssertTrue(app.navigationBars["Profile"].exists)
}
private func openFromSafari(_ urlString: String) {
    let safari = XCUIApplication(bundleIdentifier: "com.apple.mobilesafari")
    safari.launch()
    // Make sure Safari is really running before asserting
    XCTAssert(safari.wait(for: .runningForeground, timeout: 5))
    // Type the deeplink and execute it
    let firstLaunchContinueButton = safari.buttons["Continue"]
    if firstLaunchContinueButton.exists {
        firstLaunchContinueButton.tap()
    }
    safari.buttons["URL"].tap()
    let keyboardTutorialButton = safari.buttons["Continue"]
    if keyboardTutorialButton.exists {
        keyboardTutorialButton.tap()
    }
    safari.typeText(urlString)
    safari.buttons["Go"].tap()
    _ = confirmationButton.waitForExistence(timeout: 2)
    if confirmationButton.exists {
        confirmationButton.tap()
    }
}

It’s good to add the additional wait(for: .runningForeground) assertion for safety, as that makes the test check that the app switching actually worked before attempting to assert anything else. If it fails for some reason, you'll know it was because the app failed to switch instead of something not being present in the UI of your app.

为了安全起见,最好添加额外的wait(for: .runningForeground)断言,因为这样可以在尝试断言其他任何事情之前测试应用切换是否确实有效。 如果由于某种原因它失败了,您会知道这是因为该应用程序无法切换,而不是您的应用程序UI中不存在某些内容。

You may also notice that there’s some additional logic in our Safari handling. Safari sometimes shows a “What’s new” screen, which we treat by first finding and tapping the "Continue" button if it exists, which can also happen when opening the keyboard at the same time. Additionally, when executing deep links you might sometimes get an "Open in X?" confirmation, which is treated by finding and tapping the "Open" button.

您可能还会注意到,我们的Safari处理中还有一些其他逻辑。 Safari有时会显示“新功能”屏幕,我们将首先查找并点按"Continue"按钮(如果存在)来进行处理,这在同时打开键盘时也会发生。 此外,执行深层链接时,有时可能会显示“在X中打开?”。 确认,方法是找到并点击"Open"按钮。

UI测试深层链接(启动应用程序/从被终止的应用程序启动) (UI Testing Deep Links (That Launch the App/From a Killed App))

The issue I faced that prompted me to write this article is that iOS processes deep links differently according to the current state of the app. For example, in SceneDelegates, deep links will trigger your scene(_:openURLContexts:) method. But if the app is launched as a result of the deep link, no method is called. Instead, you need to access it from the urlContexts property of your scene. Thus, when UI testing, you also need to have a test that operates on an app that is not running.

我遇到的促使我写这篇文章的问题是,iOS根据应用程序的当前状态处理深层链接的方式有所不同。 例如,在SceneDelegates ,深层链接将触发您的scene(_:openURLContexts:)方法。 但是,如果应用是由于深层链接而启动的,则不会调用任何方法。 相反,您需要从场景的urlContexts属性访问它。 因此,在进行UI测试时,您还需要进行在运行的应用程序上运行的测试。

One may think that a UI test would fail if your app terminates, but that’s actually not the case! You can make a test that terminates and reboots an app as much as you like by using these special methods from XCUIApplication:

有人可能会认为,如果您的应用终止,则UI测试将失败,但实际上并非如此! 通过使用XCUIApplication以下特殊方法,您可以根据需要进行终止和重新启动应用程序的测试:

app.launch() // Launches the app (or reboots it/launches it again)
app.terminate() // Terminates the app (which does not stops the test!)
app.actviate() // Puts the app in the foreground, if it was backgrounded

As mentioned, if you terminate the app, you’re free to launch it again in the same test. It’s not necessary to reassign your XCUIApplication instance. All assertions will work normally as if the app was never terminated in the first place.

如前所述,如果您终止应用程序,则可以在同一测试中再次启动它。 不必重新分配您的XCUIApplication实例。 所有断言都将正常运行,就好像该应用程序从未被终止一样。

Thus, to test that our deep links work correctly when the app isn’t launched, we can simply close the app before opening Safari. It’s not necessary to launch it again, as that will happen naturally as iOS attempts to open our deep link.

因此,要测试未启动应用程序时我们的深层链接能否正常工作,我们可以在打开Safari之前先关闭应用程序。 无需再次启动它,因为随着iOS尝试打开我们的深层链接,这自然会发生。

func testDeeplinkFromSafari_fromBackgroundedApp() {
    openSafariDeeplink(terminateFirst: false)
}
func testDeeplinkFromSafari_thatLaunchesTheApp() {
    openSafariDeeplink(terminateFirst: true)
}
func openSafariDeeplink(terminateFirst: Bool) {
    let app = XCUIApplication()
    app.launch()
    if terminateFirst {
        app.terminate()
    }
    // Launch Safari and deeplink back to our app
    openFromSafari("swiftrocks://profile")
    // Make sure Safari properly switched back to our app before asserting
    XCTAssert(app.wait(for: .runningForeground, timeout: 5))
    // Assert that the deeplink worked by checking if we're in the "Profile" screen
    XCTAssertTrue(app.navigationBars["Profile"].exists)
}

An alternative for this is to simply never call app.launch(), but I had mixed results with it. Launching the app also installs it, so never launching it resulted in flaky tests. Launching and terminating it, however, works 100% of the time.

一种替代方法是根本不调用app.launch() ,但是我将结果混合在一起。 启动该应用程序还会安装该应用程序,因此切勿启动它导致不稳定的测试。 但是,启动和终止它的时间是100%。

UI测试通用链接(从后台应用程序) (UI Testing Universal Links (From a Backgrounded App))

The testing process of universal links is very similar to that of deep links, with an important difference: For some reason, universal links don’t work in the simulator’s Safari. It’s unclear if that’s on purpose or if it’s really a bug, but while universal links work fine on your device’s Safari, they will not work on the simulator’s one.

通用链接的测试过程与深层链接的测试过程非常相似,但有一个重要区别:出于某种原因,通用链接在模拟器的Safari中不起作用。 尚不清楚这是故意的还是真正的错误,但是虽然通用链接在设备的Safari上可以正常使用,但在模拟器的Safari上却无法使用。

This means we unfortunately can’t use our Safari wrapper for them, but luckily, you can still test universal links by using the Messages app. We can then test our universal links by opening the Messages app, clicking on a contact, sending them a universal link, and tapping the newly sent message’s link bubble to trigger it.

不幸的是,这意味着我们不能为它们使用Safari包装器,但是幸运的是,您仍然可以使用Messages应用程序测试通用链接。 然后,我们可以通过以下方法测试通用链接:打开“消息”应用程序,单击联系人,向他们发送通用链接,然后点击新发送的消息的链接气泡以触发它。

To launch Messages, we use the bundle identifier "com.apple.MobileSMS".

要启动消息,我们使用包标识符"com.apple.MobileSMS"

private func openFromMessages(_ urlString: String) {
    let messages = XCUIApplication(bundleIdentifier: "com.apple.MobileSMS")
    messages.launch()
    XCTAssert(messages.wait(for: .runningForeground, timeout: 5))
    // Dismiss "What's New" if needed
    let continueButton = messages.buttons["Continue"]
    if continueButton.exists {
        continueButton.tap()
    }
    // Dismiss iOS 13's "New Messages" if needed
    let cancelButton = messages.navigationBars.buttons["Cancel"]
    if cancelButton.exists {
        cancelButton.tap()
    }
    // Open the first available chat
    let chat = messages.cells.firstMatch
    XCTAssertTrue(chat.waitForExistence(timeout: 5))
    chat.tap()
    // Tap the text field
    messages.textFields["iMessage"].tap()
    // Dismiss Keyboard tutorial if needed
    let keyboardTutorialButton = messages.buttons["Continue"]
    if keyboardTutorialButton.exists {
        keyboardTutorialButton.tap()
    }
    messages.typeText("Link: \(urlString)")
    messages.buttons["sendButton"].tap()
    let bubble = messages.links.firstMatch
    XCTAssertTrue(bubble.waitForExistence(timeout: 5))
    sleep(3)
    bubble.tap()
}

The logic to open a link from Messages is a little longer because it sometimes takes a couple more taps before being able to click our link. In this case, we may need to dismiss up to three onboarding screens before being able to send a message. Additionally, before tapping the link, we sleep(3) to give iOS enough time to load our app's metadata. If you don't wait, sometimes iOS will fail to properly open your app.

从“消息”中打开链接的逻辑要更长一些,因为有时需要多点击几次才能单击我们的链接。 在这种情况下,我们可能需要先关闭多达三个入门屏幕,然后才能发送消息。 此外,在点击链接之前,我们进行sleep(3)以便为iOS提供足够的时间来加载应用程序的元数据。 如果您不等待,有时iOS将无法正确打开您的应用程序。

The result, however, is the same from when we tested deep links in Safari. When you call this method, iOS will switch to Messages and attempt to switch back to your app via your universal link.

但是,结果与我们在Safari中测试深层链接时的结果相同。 当您调用此方法时,iOS将切换到消息并尝试通过通用链接切换回您的应用。

func testUniversalLinkFromMessages() {
    // Launch our app
    let app = XCUIApplication()
    app.launch()
    // Launch Messages and univesal link back to our app
    openFromMessages("https://swiftrocks.com/profile")
    // Make sure Messages properly switched back to our app before asserting
    XCTAssert(app.wait(for: .runningForeground, timeout: 5))
    // Assert that the universal link worked by checking if we're in the "Profile" screen
    XCTAssertTrue(app.navigationBars["Profile"].exists)
}

UI测试通用链接(启动应用程序/从被终止的应用程序启动)(UI Testing Universal Links (That Launch the App/From a Killed App))

Like with deep links, iOS’s behavior differs slightly when launching your app as a result of tapping a universal link. When using SceneDelegates, for example, you need to instead fetch them from a scene’s userActivities property.

与深层链接一样,由于点击通用链接,因此在启动应用程序时,iOS的行为略有不同。 例如,在使用SceneDelegates ,您需要改为从场景的userActivities属性中获取它们。

To confirm that our app can properly handle this, we can use the same trick we used for the deep links and terminate our app before executing the test.

为了确认我们的应用程序可以正确处理此问题,我们可以使用与深层链接相同的技巧,并在执行测试之前终止我们的应用程序。

func testUniversalLinkFromMessages_fromBackgroundedApp() {
    openMessagesUniversalLink(terminateFirst: false)
}
func testUniversalLinkFromMessages_thatLaunchesTheApp() {
    openMessagesUniversalLink(terminateFirst: true)
}
func openMessagesUniversalLink(terminateFirst: Bool) {
    let app = XCUIApplication()
    app.launch()
    if terminateFirst {
        app.terminate()
    }
    // Launch Messages and univesal link back to our app
    openFromMessages("https://swiftrocks.com/profile")
    // Make sure Messages properly switched back to our app before asserting
    XCTAssert(app.wait(for: .runningForeground, timeout: 5))
    // Assert that the universal link worked by checking if we're in the "Profile" screen
    XCTAssertTrue(app.navigationBars["Profile"].exists)
}

翻译自: https://medium.com/better-programming/ui-testing-deep-links-and-universal-links-in-ios-a6052ac65039

ios ui自动化测试

安装Docker安装插件,可以按照以下步骤进行操作: 1. 首先,安装Docker。可以按照官方文档提供的步骤进行安装,或者使用适合您操作系统的包管理器进行安装。 2. 安装Docker Compose插件。可以使用以下方法安装: 2.1 下载指定版本的docker-compose文件: curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose 2.2 赋予docker-compose文件执行权限: chmod +x /usr/local/bin/docker-compose 2.3 验证安装是否成功: docker-compose --version 3. 在安装插件之前,可以测试端口是否已被占用,以避免编排过程中出错。可以使用以下命令安装netstat并查看端口号是否被占用: yum -y install net-tools netstat -npl | grep 3306 现在,您已经安装Docker安装Docker Compose插件,可以继续进行其他操作,例如上传docker-compose.yml文件到服务器,并在服务器上安装MySQL容器。可以参考Docker的官方文档或其他资源来了解如何使用DockerDocker Compose进行容器的安装和配置。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Docker安装docker-compose插件](https://blog.youkuaiyun.com/qq_50661854/article/details/124453329)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [Docker安装MySQL docker安装mysql 完整详细教程](https://blog.youkuaiyun.com/qq_40739917/article/details/130891879)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值