什么是 GTXiLib?
GTXiLib 是针对 iOS 平台的 Google Toolbox for Accessibility,简称 GTX-eye。这是一个用于 iOS 可访问性测试的框架。GTXiLib 集成 XCTest,可以与任何基于 XCTest 的框架(例如 EarlGrey)一起使用。GTXiLib 通过在其上安装“可访问性检查”来提高您测试的价值;您的现有测试用例可以不修改其他代码就作为可访问性测试使用。GTXiLib 通过勾入测试清理过程并在屏幕上的所有元素上调用已注册的可访问性检查(例如检查是否存在可访问性标签)来实现这一点。
入门
要将 GTXiLib 安装到特定测试类中所有测试的代码片段添加到其中。
// Include the GTXiLib umbrella header.
// Note that that is +setUp not -setUp
+ (void)setUp {
[super setUp];
// ... your other setup code (if any) comes here.
// Create an array of checks to be installed.
NSArray *checksToBeInstalled = @[
[GTXChecksCollection checkForAXLabelPresent]
];
// Install GTX on all tests in *this* test class.
[GTXiLib installOnTestSuite:[GTXTestSuite suiteWithAllTestsInClass:self]
checks:checksToBeInstalled
elementExcludeLists:@[]];
}
安装后,GTX 将在测试用例 tearDown 之前运行所有注册的可访问性检查,如果任何可访问性检查失败,则将使测试失败。使用上面的代码片段,您的测试现在将开始捕获在您的应用中添加 UI 元素时忘记了设置可访问性标签的问题。
在上面的代码片段中,我们只安装了 checkForAXLabelPresent
,但您也可以从 GTXChecksCollection 中安装多个检查,也可以包含您自己的自定义检查。
// Inside +setUp ...
// Create a new check (for example that ensures that all AX label is not an image name)
id<GTXChecking> myNewCheck =
[GTXCheckBlock GTXCheckWithName:@"AXlabel is not image name"
block:^BOOL(id element, GTXErrorRefType errorPtr) {
// Ensure accessibilityLabel does not end with .png
return ![[element accessibilityLabel] hasSuffix:@".png"];
}];
// Create an array of checks to be installed.
NSArray *checksToBeInstalled = @[
[GTXChecksCollection checkForAXLabelPresent],
[GTXChecksCollection checkForAXTraitDontConflict],
myNewCheck,
];
// Install GTX on all tests in *this* test class.
[GTXiLib installOnTestSuite:[GTXTestSuite suiteWithAllTestsInClass:self]
checks:checksToBeInstalled
elementExcludeLists:@[]];
注意,GTX 是添加到 +setUp
方法,而不是实例方法 -setUp
,因为 GTX 只需要在给定的测试运行时安装一次。
要添加 GTXiLib 到您的项目,请使用 cocoapods。
Podfile
如果通过CocoaPods安装,您需要在Podfile中将GTXiLib
作为一个依赖项添加。由于GTXiLib
只在测试过程中运行,因此不要将其添加到主应用spec中。此外,CocoaPods不再需要use_frameworks!
。使用use_frameworks!
会导致构建失败并出现错误ld: framework not found
。您的Podfile应该像这样
target 'myapp' do
# Configuration for app myapp
# Note the lack of use_frameworks!
target 'myappTests' do
inherit! :search_paths
# Pods for testing
pod 'GTXiLib'
end
end
CocoaPods and Swift
GTXiLib支持Swift项目。安装说明几乎与Objective-C项目相同。您的Podfile
应该像这样
use_modular_headers!
target "NameOfYourProject" do
pod "GTXiLib"
end
带有“GTXiLib”的可选版本指定符。注意use_modular_headers!
行和use_frameworks!
的缺失。从CocoaPods 1.5.0开始,Swift项目不再需要use_frameworks!
。使用use_frameworks!
会使Abseil
(GTXiLib的依赖项)无法正确导入。因此,您不能使用use_frameworks!
,这意味着您必须使用use_modular_headers!
。您还可以为每个pod指定:modular_headers => true
。然后,将import GTXiLib
添加到Swift文件中,并可以使用GTXiLib API。
如果项目不包含Swift文件,use_modular_headers!
是可选的。
增量可访问性
GTXiLib API支持一种实用的解决方案,以提高一开始可能没有包括可访问性的大型项目的可访问性 -- 增量可访问性。将GTXiLib添加到开发已经进行了一半的项目可能会导致多个测试失败,一次修复它们既耗时又繁琐。要增量解决这个问题
- 使用上面的片段将GTXiLib添加到所有测试用例中,但修复其中一小部分错误。
- 使用GTXiLib的excludeList API排除您无法控制的元素。
- 然后使用
GTXTestSuite
的suiteWithClass:andTests:
方法创建只包含已修复测试用例的测试套件,并将 GTXiLib 仅添加到该套件。
一旦代码被提交到您的仓库,GTXiLib 将捕获这些测试中的任何新失败。从此点开始
- 每个新增的测试都必须添加到套件中。
- 根据团队优先级,继续移动现有测试到套件中,直到所有方法都在套件中。
如果测试类的所有测试都已在套件中,请使用 suiteWithAllTestsInClass:
方法而不是列出演示方法,这也确保新添加到类中的方法自动进行可访问性检查。
如果您的项目中每个测试都安装了 GTXiLib,请使用 suiteWithAllTestsFromAllClassesInheritedFromClass:
自动将可访问性检查添加到任何新增的测试用例。
编写您自己的检查
GTXiLib 有 API 允许您创建自己的可访问性检查(实际上它不必与可访问性相关,例如 i18n 布局检查甚至内存使用检查)。要创建新的检查,请使用 GTXiLib 的 checkWithName:block:
API,并提供一个唯一的名字和块来评估检查,并返回 YES/NO 以表示成功/失败。将新创建的检查添加到通过 install API 调用传递给 GTXiLib 的检查数组。
处理 GTXiLib 失败
当 GTXiLib 失败时,它很可能找到了一个可访问性错误,您必须修复它。但由于各种团队优先级,可能无法立即修复,在这种情况下,您有以下选择
- 使用
suiteWithAllTestsInClass:exceptTests:
暂时排除测试用例。 - 使用元素排除列表 API 暂时排除违规元素。
但如果你认为 GTXiLib 捕获到的错误不是可访问性问题,请通过 提交错误 或更好地 修复它 以供每个人。
将 GTXiLib 集成到自定义测试框架
如果您是测试 框架 开发者,您可以使用 GTXToolKit 类将无障碍检查功能集成到您的测试框架中。GTXiLib 的自研 XCTest 集成也是基于 GTXToolKit 提供的 API 构建的。使用 GTXToolKit 对特定元素执行无障碍检查的步骤包括
- 创建一个 GTXToolKit 对象。
- 将其与一系列检查关联起来。
- 在要检查的元素上使用它。
GTXToolKit *toolkit = [[GTXToolKit alloc] init];
// Register one or more built in checks:
[toolkit registerCheck:[GTXChecksCollection checkForAXLabelPresent]];
[toolkit registerCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]];
// and/or add a couple of your own:
id<GTXChecking> fooCustomCheck =
[GTXCheckBlock GTXCheckWithName:@"AXlabel is not image name"
block:^BOOL(id element, GTXErrorRefType errorPtr) {
// Check logic comes here...
return YES;
}];
[toolkit registerCheck:fooCustomCheck];
// Use the toolkit on an element.
NSError *error;
BOOL success = [toolkit checkElement:someElement error:&error];
if (!success) {
NSLog(@"Element FAILED accessibility checks! Error: %@",
[error localizedDescription]);
} else {
NSLog(@"Element PASSED accessibility checks!");
}
GTXToolKit 对象也可以通过仅提供根元素来应用于元素树。
// Use the toolkit on a tree of elements by providing a root element.
NSError *error;
BOOL success = [toolkit checkAllElementsFromRootElements:@[rootElement]
error:&error];
if (!success) {
NSLog(@"One or more elements FAILED accessibility checks! Error: %@",
error);
} else {
NSLog(@"All elements PASSED accessibility checks!");
}
在调用 checkAllElementsFromRootElements:
时,您可能希望因各种原因忽略某些元素,您可以使用 GTXToolKit 的 ignore
API 完成。
- (void)ignoreElementsOfClassNamed:(NSString *)className;
- (void)ignoreElementsOfClassNamed:(NSString *)className
forCheckNamed:(NSString *)skipCheckName;
注意,checkAllElementsFromRootElements:
需要一个 数组 的根元素,而不是单个元素。以下代码示例展示了如何对屏幕上的所有元素运行检查
// Run the checks on all elements on the screen.
[toolkit checkAllElementsFromRootElements:@[[UIApplication sharedApplication].keyWindow]
error:&error];
如需完整最新参考,请查阅 GTXToolKit.h 文件。
数据分析
为了优先考虑和改进 GTXiLib,框架收集使用数据并将其上传到 Google Analytics。具体来说,框架收集了测试应用 Bundle ID 的 MD5 哈希和 GTXiLib 检查的通过/失败状态。这些信息使我们能够衡量使用量。有关我们分析集成的更多详细信息,请阅读包含实现细节的 GTXAnalytics.m
文件。用户可以选择在测试的 +(void)setUp
方法中添加以下代码片段以禁用分析退出
// Disable GTXiLib analytics.
[GTXAnalytics setEnabled:NO];
讨论
请加入我们的 ios-accessibility Google 群组,讨论所有无障碍相关话题,并跟踪 GTXiLib 的所有更新。
贡献者
在做出任何贡献之前,请确保您已遵循CONTRIBUTING.md中的指南。
注意:这并非官方的Google产品。