使用XCTestplan和Xcode 11的自动iOS屏幕截图

Raiffeisenbank中有几个移动应用程序可以在各种设备和操作系统上运行,因此我们尝试使测试中的常规过程自动化。这篇文章对我们来说似乎很有用,因此我们决定将其翻译。照片来源:unsplash.com 如果您的应用程序是多语言的,通用的并且针对不同的设备设计的,那么您可以花费大量时间为每种配置创建屏幕截图。假设您有四种语言,支持iPad和iPhone,并且每个屏幕需要保存4个屏幕-这是32个屏幕截图。该过程必须是自动化的,以免在每次更新接口时浪费时间。






Xcode 11中出现的XCTestPlan工具允许我们为测试创建几种配置。如今,配置最常用于确定测试的运行方式,包括为应用程序选择语言。在本文中,您将学习如何使用XCTestPlan自动执行屏幕截图。

启动XCTestplan


让我们设置一个单独的UITests目标来自动创建屏幕截图,如果您不打算使用这些配置运行主要测试,则该功能特别有用。要创建一个新目标,请选择File-> New-> Target并创建一个新的UI Testing Bundle。之后,您需要向该目标添加一个新的XCTestplan。为此,您可以使用菜单产品->测试计划->新测试计划,或在方案编辑器中选择转换以使用测试计划。如果通过菜单执行此操作,则需要确保新目标位于“测试”标签上。

由于我们只想配置语言设置,因此我们可以保持“共享设置”不变,而只需为我们支持的每种语言添加一个新配置。支持英语,德语和法语的应用程序的设置如下所示:

图片

这是XCTestplan的所有必需的设置和启动。

屏幕截图自动化


创建屏幕截图的UI测试与常规测试几乎没有什么不同,只是它们会创建附件。您还可以添加XCTAssert检查,以便在出现问题时测试失败。

另一个要点:如果在截屏时您的UI尚未准备好键盘显示 /隐藏,动画完成),则可能需要waitForExpectations

下面是所有辅助方法的示例:

func testScreenshots() {
    let app = XCUIApplication()
    let searchButton = app.buttons["search"]
    searchButton.tap()
    
    let keyboard = app.keyboards.firstMatch
    waitForExistence(of: keyboard)
    app.typeText("Cupertino")
    add(takePromoShot(name: "Search"))
    
    let firstResult = app.cells.firstMatch
    firstResult.tap()
    waitForDisappearance(of: keyboard)
    add(takePromoShot(name: "Result"))
}

func waitForExistence(of element: XCUIElement) {
    let predicate = NSPredicate(format: "exists == TRUE")
    expectation(for: predicate, evaluatedWith: element, handler: nil)
    waitForExpectations(timeout: 5.0, handler: nil)
}

func waitForDisappearance(of element: XCUIElement) {
    let predicate = NSPredicate(format: "exists == FALSE")
    expectation(for: predicate, evaluatedWith: element, handler: nil)
    waitForExpectations(timeout: 5.0, handler: nil)
}

func takePromoShot(name: String) -> XCTAttachment {
    let lang = Locale.preferredLanguages[0]
    let screenshot = XCUIScreen.main.screenshot()
    let attachment = XCTAttachment(screenshot: screenshot)
    attachment.lifetime = .keepAlways
    attachment.name = "\(lang)-\(name)"
    return attachment
}

注意最新功能。它获取快照的名称,添加语言标识符,获取屏幕快照,并返回带有.keepAlways参数值的XCTAttachment这很重要,因为默认情况下,如果测试成功,则会删除测试过程中截取的屏幕截图。Lifiteme是一个重要的参数,因为它可确保在测试完成后保存屏幕截图。在UI测试期间,会不断拍摄屏幕截图。当您需要确定测试失败的原因和时间时,它们非常有用。但默认情况下,如果测试成功,屏幕截图将被删除。因此,当testScreenshots()成功时,您将只有必要的屏幕截图。

习惯状态栏


大多数开发人员更喜欢在屏幕截图上看到带有正确时间的状态栏,完整的网络信号和其他详细信息。在Xcode 11中,这变得更加容易。有一个实用程序xcrun simctl status_bar,它允许您指定这些设置。可以将其添加为构建阶段

xcrun simctl status_bar booted override --time 9:41 --operatorName ' ' --cellularMode active --cellularBar 4 --wifiBars 3 --batteryState charged

执行此命令后,状态栏的外观将与Apple的营销材料相同。不幸的是,团队不会在真实的设备上工作,只能在模拟器上工作。还应注意,在开始测试以收集屏幕截图之前,您使用的模拟器必须正在运行。

收集结果截图


现在我们可以运行UI测试了。当它们通过时,我们将在Xcode的Report Navigator看到结果也将有包含按语言配置分组的过程的测试。带有附件的过程都用回形针标记。图像本身可以在QuickLook中打开

图片

单独收集所有生成的图片可能非常耗时,尤其是在您的应用程序支持多种语言的情况下。不幸的是,这些附件在测试结果中没有显示为png或jpg(Xcode 11中的另一个更改)。但是您可以解析测试结果,并找到指向实际附件的JSON并收集它们。可以使用xcparse实用程序来完成它使用Homebrew安装并通过以下命令启动:

xcparse screenshots /path/to/Test.xcresult /path/to/outputDirectory

其他标志将按设备,操作系统或配置对文件进行分组。我们文件的名称包含语言标识符,因此您只需按名称对它们进行排序。

结论


所描述的方法已经使我们节省了足够的时间,特别是在需要以新分辨率支持设备或接口被显着更新的情况下。在WWDC20上,我希望看到设备的选择是XCTestplan配置的一部分,但是现在,您必须手动选择或使用脚本来收集AppStore中的必要屏幕截图。

All Articles