如何在 XCUITest 期间为多个 UIPickerView 指定可访问性标识符

How to specify accessibility identifiers for multiple UIPickerViews during XCUITest

在为具有多个 UIPickerView 的视图控制器开发 Xcode UI 测试用例时,我 运行 遇到了几个阻止成功的错误,所有这些都与能够唯一标识XCUITest.

中的选择器

"should" 的工作是简单地从故事板中设置可访问性标识符或可访问性标签,如下所示:

但这对于 UIPickerView 根本不起作用,尽管我验证了 UIPickerView 的 accessibilityLabel 和 accessibilityIdentifier 属性设置。是的,我尝试了一套或另一套或两套。我什至尝试以编程方式设置一个或另一个或两者。 XCUI测试用例中的以下行无论如何都无法找到选择器:

  XCUIElement *shippingMethodPicker = app.pickerWheels[@"Shipping method"];
 [shippingMethodPicker adjustToPickerWheelValue:@"USPS Media Mail"];

这似乎是一个已知问题,解决方案是使视图控制器也成为 UIPickerViewAccessibilityDelegate,并实现 - (NSString *)pickerView:(UIPickerView *)pickerView accessibilityLabelForComponent:(NSInteger)组件委托方法。

Apple API Documentation 似乎准确描述了我们需要什么才能将可访问性标签唯一地应用到每个 pickerWheels 组件。

但这也有问题,pickerView 参数实际上不是 UIPickerView *,如本 Whosebug 中所引用 link Unable to get pickerView.tag in -pickerView:accessibilityLabelForComponent: method

由于委托方法的实现缺陷,您无法确定正在调用哪个 UIPickerView 委托,以使其对于具有多个选择器的视图无效。

由于故事板方法有问题,可访问性委托也有问题,我无法找到一种方法来从 XCUITest 中的视图控制器中唯一标识两个或多个 UIPickerView测试用例。

有人有解决办法吗?

根据之前的 Whosebug link 评论,我确定了一个适合我的要求的解决方案。

从调试器我们可以确认之前的link评论观察:

可访问性委托方法,

- (NSString *)pickerView:(UIPickerView *)pickerView accessibilityLabelForComponent:(NSInteger)component;

有很多问题,没有 UIPickerView *,而是私有的 class UIAccessibilityPickerComponent *。正如我们在调试器中注意到的那样,在这个私有 class.[=14 的私有 _picker 属性 中有一个实际的 UIPickerView * =]

雷达打开。

好吧,这是一个内部测试问题,我们不会在 App Store 的应用程序中发布它。所以我们可以使用私有接口来解决这个问题。我们只会在执行 UI 测试时编译它。

首先,在 Xcode 中创建一个仅用于测试的新构建配置,从调试中复制。在其中创建一个新的预处理器定义 -DXCUITEST 并确保在您的测试方案中设置这个新的构建配置。

然后按如下方式实现可访问性委托:

#pragma mark - UIPickerViewAccessibilityDelegate

#ifdef XCUITEST
- (NSString *)pickerView:(UIPickerView *)pickerView accessibilityLabelForComponent:(NSInteger)component {

    NSString *label;
    UIPickerView *realPickerView;
    Ivar picker;

    // we are going to work around a bug where the pickerView on this delegate is the wrong class by
    // pulling the UIPickerView * that we need from the private property of the UIAccessibilityPickerComponent class
    picker = class_getInstanceVariable([NSClassFromString(@"UIAccessibilityPickerComponent") class], "_picker");

    // check if the bug still exists and apply workaround only if necessary
    if (![pickerView isKindOfClass:[UIPickerView class]])
        realPickerView = object_getIvar(pickerView, picker);
    else
        realPickerView = pickerView;  

    if (realPickerView == self.shippingMethod)
        label = @"Shipping method";
    else if (realPickerView == self.someOtherPicker)
        label = @"SomeOtherPicker";

    return label;
}
#endif

有了这个解决方法,XCUITest 测试用例最终 按预期执行,成功地在单个视图上测试了两个甚至三个 UIPickerView 的情况所有唯一标识。请注意,在我的例子中,这些是单轮选择器,如果你想解决 multi-wheel 选择器的问题,然后在委托中实现 component 逻辑,它没有被窃听并且可以工作不出所料。

此外,不要忘记将此 header 添加到视图控制器 class 文件的顶部:

#ifdef XCUITEST
#import <objc/runtime.h>
#endif