我的 XCode UI 测试如何检测到屏幕发生了变化?

Posted

技术标签:

【中文标题】我的 XCode UI 测试如何检测到屏幕发生了变化?【英文标题】:How can my XCode UI test detect that the screen has changed? 【发布时间】:2015-12-16 19:57:52 【问题描述】:

我正在尝试使用 XCode 7 的 XCTest UI 测试功能创建一个树遍历器,该功能系统地探索表视图的确定性树到指定深度。它几乎可以工作,除了我无法可靠地检测到任何给定元素上的点击是否实际上触发了到新屏幕的转换。我有一个在大多数情况下都有效的 hacky 方法,即检测导航栏标签是否已更改或菜单元素的数量已更改。

第一个测试有误报,因为连续的屏幕可以有相同的导航栏标签(我正在走的代码库不是我的)。第二个测试有误报,因为有时单击表格元素不会转换到另一个表格/屏幕,而是会向当前屏幕添加额外的元素。

在做了一些阅读之后,似乎使用可访问性标签可能是要走的路。因此,我在应用程序代码中(在 viewDidAppear 中)为导航栏的可访问性标签设置了一个 UID,然后在 UI 测试代码中对其进行测试。感觉这应该可以工作,但我只能在测试代码中返回 nil 值。

我坦白承认,在 UI 测试方面,我是个菜鸟,主要是剪切/粘贴/改编其他人的代码,而没有清楚地了解自己在做什么。因此,我可能在可访问性标签代码本身以及检测屏幕已更改的概念级别上犯了某种天真的错误;也许我可以做一些更简单/更惯用的事情。

在应用程序中:

- (void)viewDidAppear: (BOOL)animated 

    [super viewDidAppear: animated];

    //...

    UINavigationBar* navBar = self.navigationController.navigationBar;
    if( navBar )
    
        static NSInteger s_UID = 0;
        navBar.topItem.accessibilityLabel = [NSString stringWithFormat:@"UID-%ld", s_UID++];
    

在 XCTest UI 测试中:

- (NSString*) navBarAccessibilityLabel: (XCUIApplication*) app

    NSString* result = NULL;

    XCUIElementQuery *navBars = app.navigationBars;
    XCUIElement* firstElem = [navBars.staticTexts elementBoundByIndex:0];
    if( firstElem )
    
        result = (NSString*)firstElem.accessibilityLabel; // This is always nil
    

    return result;

请注意,找到了 firstElem,并且我能够提取例如firstElem.label 从中非常高兴。

任何帮助表示赞赏。

【问题讨论】:

你有什么解决办法吗? @Kaitain? 【参考方案1】:

您可以测试元素是否可访问:

在 UI 测试中左键单击并开始录制,模拟器将启动,您可以单击模拟器中的元素,如果该元素可访问,Xcode 将在 testExample 方法中为您编写测试代码。

或者在模拟器中运行您的应用并打开辅助功能检查器,然后将鼠标悬停在元素上,因为详细信息将显示在检查器中。

除此之外,我认为在您的情况下,您可以通过为每个屏幕添加导航项标题来验证这一点,即self.navigationItem.title = @"myScreen";

然后用断言验证屏幕,即

// let app = XCUIApplication() // Swift

UIApplication *app = [UIApplication alloc] init]; // Objective-C

XCTAssertEqual(app.navigationBars.element.identifier, "myScreen") // Don't forget to import class XCTest

【讨论】:

这绝对有用。谢谢。但是,据我所知,这会改变屏幕上实际可见的标题。我希望可以添加某种不可见的标签,根本不会改变可观察值。 (好吧,我意识到最终所有可访问性数据都应该以某种形式可以观察到,即使它是音频。)【参考方案2】:

假设您已为视图控制器提供了正确的标识符(以便您可以区分它们),您可以将其添加到相关的视图控制器中:

#ifdef UITESTING
- (void) viewDidAppear: animated

  [super viewDidAppear: animated];
  // do your checking here

#endif

在您项目的测试目标中,在构建设置下有一个 Proprocessor 部分。在那里你可以设置预处理器宏。只需将“UIESTING=1”添加到调试和/或发布设置。效果是在您的测试构建中将定义 UIESTING,因此#ifdef UITESTING 下的所有代码都将被预处理器包含。

【讨论】:

澄清一下,这段代码是在 UI 测试程序中,还是在主应用程序代码中? 这将是您应用程序代码的补充,以支持测试。我猜一些适当的#ifdef 可以将它排除在您的生产代码之外。 好吧...我觉得我错过了什么。什么样的逻辑打算进入“//你在这里检查”?为什么我要检查应用程序代码中的某些内容?我曾假设应用程序代码需要对某物应用某种标识符标签,并且 UI 测试代码稍后会利用它来检测屏幕变化。我无法立即看到您提出的解决此问题(或为检测屏幕更改的更普遍问题提供解决方案)的有用性。将此逻辑排除在生产代码之外并不是主要问题。 您将问题表述为“我无法可靠地检测到对任何给定元素的点击是否实际上触发了到新屏幕的转换”。所以简而言之,我的回答是:使用 viewDidAppear 回调在打开新屏幕时获得通知。这就是问题的确切答案。 这些信息是如何传达给 XCTest UI 测试过程的? (顺便问一下,你熟悉使用 XCTest 吗?)【参考方案3】:

我会使用Facebook's Snapshot test library 进行快照测试。

基于视图的测试意味着验证用户看到的就是您所看到的 想让用户看到。这样做意味着能够确保 你的观点的不同版本,或者你观点的不同状态, 继续看起来一样。基于视图的测试可用于提供 涵盖围绕对象的许多用例的高级测试。

您可以找到更详细的精彩文章here.

【讨论】:

以上是关于我的 XCode UI 测试如何检测到屏幕发生了变化?的主要内容,如果未能解决你的问题,请参考以下文章

在 UI 测试期间,如何使用 Xcode 7 截取我的 UI 截图?

如何检测键盘是不是显示在 Xcode UI 测试中

如何在 iOS Xcode UI 测试用例中启动系统应用

如何在 Xcode UI 测试中获得授权部分

Xcode - 如何检测 iPhone 的屏幕尺寸 [关闭]

Xcode 11.1 尝试在 Safari 浏览器的登录屏幕中记录以编写 UI 测试时崩溃