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

时间:2017-06-01 01:50:35

标签: objective-c xcode8 accessibility uipickerview xcode-ui-testing

在为具有多个UIPickerViews的视图控制器开发Xcode UI测试用例时,我遇到了一些阻止成功的错误,这些错误都与能够在XCUITest中唯一识别选择器有关。

"应该"工作就是在故事板中简单地设置辅助功能标识符或辅助功能标签,如下所示:

enter image description here

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

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

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

Apple API Documentation似乎准确描述了为每个pickerWheels组件唯一应用辅助功能标签所需的内容。

但这也有问题,pickerView参数实际上并不是UIPickerView *,正如此stackoverflow链接Unable to get pickerView.tag in -pickerView:accessibilityLabelForComponent: method

中所引用的那样

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

由于故事板方法被窃听,并且可访问性委托也被窃听,我找不到从XCUITest测试用例中在视图控制器中唯一标识两个或更多UIPickerView的方法。

任何人都有解决方案吗?

1 个答案:

答案 0 :(得分:0)

关注以前的stackoverflow链接评论,我确定了一个适合我的要求的解决方案。

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

enter image description here

辅助功能委托方法

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

非常缺陷,没有UIPickerView *,而是私有类UIAccessibilityPickerComponent *。我们可以在调试器中注意到,在这个私有类的私有 _picker 属性中有一个实际的UIPickerView *。

雷达开了。

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

首先,在Xcode中创建一个新的构建配置,您只能用于测试,从Debug复制。在其中创建一个新的预处理器定义-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测试用例最终按预期执行,成功测试了两个甚至三个UIPickerViews在单个视图上的情况,这些视图都是唯一标识的。请注意,在我的情况下,这些是单轮拣货机,如果你想解决多轮拣货机的问题,那么在代表中实现组件逻辑,这没有错误并按预期工作。

另外,不要忘记将此标题添加到视图控制器类文件的顶部:

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