【问题标题】:How to drag and drop an external item for Xcode-ui-testing如何拖放外部项目以进行 Xcode-ui-testing
【发布时间】:2020-07-13 21:31:47
【问题描述】:

在我的应用程序中,我允许用户将项目从 Finder(或任何其他基于文件的 URL 源)拖放到我的应用程序中。我想做的是添加一个机制,让我可以在 Xcode UI 测试中进行测试。

我可以看到如何使用XCUIElement.press(forDuration:thenDragTo:) 在应用程序内测试源和目标的拖放,但是当拖动源在应用程序之外时,我一直无法找到测试方法。

在一个有点相关的测试中,我通过将要粘贴的字符串设置为NSPasteboard.general 来测试应用程序的复制和粘贴部分,然后使用XCUIElement.typeKey("v", modifierFlags: .command) 将其粘贴到所需的元素中。这有点不太理想,因为它取决于 Command-v 实际上是作为粘贴命令实现的,但这不太可能改变,所以它可以满足我的需要。 (事实上​​,我已经编写了一个 XCUIElement.paste(_ s: String) 扩展,这让我可以很容易地在测试中添加它。)

我相信拖放也使用NSPasteboard 进行通信,因此通过对底层机制的一些调查,我应该能够将我的对象设置到正确的粘贴板中,就像我对剪切和粘贴。我有理由确定我可以弄清楚那部分。但是我还没有弄清楚如何执行实际的下降。

我的目标是创建一个XCUIElement.drop(_ url),它将正确的“public.file-url”对象设置到正确的粘贴板中,然后模拟/执行拖放到元素中。

有什么想法吗?

我应该注意到我已经尝试了以下两个项目:

首先,我确实使用了 Xcode 记录功能来尝试记录拖放操作,看看它会给我什么事件。不幸的是,它完全没有记录。

其次,我确实有一个基于菜单的替代方案,用户可以通过文件选择器选择文件。因此,如果我可以模拟文件选择,那将是适合我目的的测试替代方案。不幸的是,我也没有在这条道路上取得任何进展。当我使用 Xcode 记录事件时,它记录了菜单选择,而对话框中实际上并没有做任何事情。

【问题讨论】:

  • 为什么XCUIElement.press(forDuration:thenDragTo:) 不起作用?
  • 我不相信press 会起作用的原因有两个。首先,我要按什么元素?那应该是源元素,但在我的情况下,源元素在应用程序之外。其次,我将如何指定要拖动的内容?据推测,这将基于作为源的元素,但正如我所提到的,我没有这样的元素。我想一种选择可能是在应用程序处于“调试”模式时创建一个不可见的标签或其他东西,并将其用作源。但这似乎是一个可怕的“黑客”。

标签: swift xcode drag-and-drop xcuitest


【解决方案1】:

根据您的 cmets,我建议您阅读这篇文章文档 https://developer.apple.com/documentation/xctest/xcuiapplication

注意init(bundleIdentifier: String)init(url: URL) 方法。这些允许您与目标应用程序以外的应用程序进行交互。

那么你可以使用XCUIElement.press(forDuration:thenDragTo:)

import XCTest
import XCTApps
import ScreenObject

let notes = XCTApps.notes.app
let photos = XCTApps.photos.app

class Tests: XCTestCase {
    func testDragAndDrop() {
        photos.launch()
        notes.launch()
        photos.images.lastMatch.press(forDuration: 1, thenDragTo: notes.textViews["Note Body Text View"])
    }
}

附:在此示例中,我使用 XCTApps 是因为我不想记住或 google 捆绑标识符:D

https://github.com/rzakhar/XCTApps

【讨论】:

  • 非常有趣。这看起来正是我想要做的。今天晚些时候我会玩这个。
  • 这肯定回答了我的问题。在我的实例中使用它不会那么容易,但我想我可以弄清楚。 (具体来说,如何从 Finder 中获取我想要的项目以便拖动它,以及如何关闭我打开的 Finder 窗口而不关闭它们。)所以我不确定我是否真的会使用它我的测试用例,但我会接受答案,因为它肯定是我问题的正确答案。
  • 我猜import ScreenObject 是什么提供了lastMatch 方法?我在 GitHub 上进行了快速搜索,但没有成功,它也没有出现在 Apple 开发人员文档中。你能提供一个在哪里找到它的参考吗?谢谢。
  • 当然!在此处获取 ScreenObject github.com/devexperts/screenobject
  • 谢谢,它看起来很有用。奇怪的是它昨天没有出现在我的搜索中。今天我重复搜索,它是列表中的第二项。
【解决方案2】:

好的,所以我还没有找到我的问题的答案(如何测试拖放),但我已经为我的测试提出了一个可接受的解决方法。

具体来说,当我更多地考虑粘贴板时,我意识到如果我允许用​​户将文件拖放到我的应用程序中,那么我也应该允许他们将文件剪切并粘贴到应用程序中。

一旦我意识到这一点,那么通过粘贴 URL 而不是拖放 URL 来测试我的应用程序的必要功能是一个相当简单的过程。这还有一个额外的好处,就是我可以将必要的测试文件添加到我的测试包中,让所有东西都很好地自包含。

为此,我在 XCUIElement 扩展中添加了以下函数:

extension XCUIElement {
    func paste(url: URL) {
        precondition(url.isFileURL, "This must be a file URL to match the pasteboard type.")
        let pasteboard = NSPasteboard.general
        pasteboard.clearContents()
        pasteboard.setString(url.absoluteString, forType: .fileURL)
        click()
        typeKey("v", modifierFlags: .command)
    }
}

然后在我的测试代码中添加以下内容来触发事件:

let mainWindow = app.windows[/*...my main window name goes here...*/]
let testBundle = Bundle(for: type(of: self))
let fileURL = testBundle.url(forResource: "Resources/simple", withExtension: "json")
mainWindow.paste(url: fileURL!)

当然,这实际上并没有测试拖放,但它确实测试了我的代码的相同部分,因为在我的 AppDelegate 中,我的 onPaste 操作方法调用了与我的 @987654325 相同的底层方法@方法。

我会等几天看看是否有人对实际问题提出了答案(因为我仍然会觉得这很有用),但如果没有人这样做,我会接受我自己的答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-02
    相关资源
    最近更新 更多