测试【免费下载链接】EarlGrey:tea: iOS UI Automation Test Framework项目地址https://gitcode.com/gh_mirrors/ea/EarlGrey点击查看免费下载本文以 EarlGrey 官方 FAQ 文档为主体系统梳理 iOS UI 自动化测试中最常遇到的高频问题与官方推荐解法。文章覆盖 EarlGrey 与 Xcode UI Testing 的架构差异、框架链接冲突、元素匹配与自定义操作、同步与动画处理、等待条件、应用状态重置、预编译 App 测试等实战场景并结合仓库源码给出可验证的实现依据。读完本文你将掌握 EarlGrey 测试中绝大多数疑难场景的标准处理方案能直接对照示例写出可运行的 Objective-C 与 Swift 测试代码。一、EarlGrey 与 Xcode UI Testing白盒与黑盒的本质差异EarlGrey 是一套白盒white-box测试方案而 Xcode 自带的 UI Testing 是黑盒black-box测试方案。这一本质区别决定了两种方案的能力边界。EarlGrey 与被测 App 运行在同一个进程中因此能够访问与被测 App 相同的内存空间。这意味着它可以做到更好的同步能力例如等待网络请求完成后再执行下一步交互支持自定义同步机制这是 Xcode UI Testing 无法实现的测试用例天然具备更强的稳定性与可重复性EarlGrey 会在 App 处于空闲状态时才执行操作。不过 EarlGrey 也有明确的限制无法在测试用例内部启动或终止被测 App而 Xcode UI Testing 可以做到这一点。此外EarlGrey 的大量交互能力依赖私有 API 来创建和注入触摸事件而 Xcode UI Testing 使用的是公开 API。值得强调的是EarlGrey 的 API 扩展性很强支持编写自定义 UI 操作Action与断言Assertion。通过 search action 机制即使元素位于可滚动容器中且需要大量滚动才能到达也能稳定地定位并操作使测试用例对 UI 变更更具弹性。相关能力可进一步参考 features.md 中关于 Synchronization 与 User-Like Interaction 的说明。二、日志中的 XXX is implemented in both YYY and ZZZ 警告与 Could not swizzle 崩溃2.1 重复链接是罪魁祸首如果你在日志中频繁看到类似 “XXX is implemented in both YYY and ZZZ. One of the two will be used. Which one is undefined.” 的警告或者测试崩溃并提示 “Could not swizzle …”这两种现象的根因通常是同一个EarlGrey 被链接了多次多份 EarlGrey 代码同时进入了运行时。标准解法是确保工程中只有Test Target依赖EarlGrey.framework并且通过Copy File(s) Build Phase将EarlGrey.framework嵌入到被测 App即$TEST_HOST中而不是让 App Target 直接链接它。具体配置步骤参考 install-and-run.md 中的手动安装章节GitHub Installation。从源码角度印证EarlGrey 在运行时会对系统方法执行 swizzle方法交换见 GREYSwizzler.m。一旦同一方法被两份 EarlGrey 实例各 swizzle 一次第二次就会抛出 “Could not swizzle” 异常。因此“只链接一次”是确保 swizzle 正常工作的前提。2.2 dyld 找不到 EarlGrey.framework如果运行时出现如下错误dyld: could not load inserted library executable_path/EarlGrey.framework/EarlGrey because image not found这说明动态加载器无法在指定路径找到EarlGrey.framework。排查思路构建 Test Target检查被测 App Bundle 中是否存在框架。对于名为MyApp的 AppEarlGrey.framework应位于MyApp.app/EarlGrey.framework。如果不存在确认 Test Target 的Build Phases中配置了Copy to $(TEST_HOST)脚本将框架拷贝到 App Bundle 内。配置方法见 install-and-run.md。重新构建后再检查若框架仍不在 App Bundle 中则需要结合工程配置与完整报错日志向官方提交 issue。三、如何“返回”或“提取”某个特定元素3.1 官方立场没有返回值 API但有更好的替代方案EarlGrey 的设计中selectElementWithMatcher:只标志一次交互的开始并不返回元素对象本身。FAQ 明确说明没有直接返回特定元素的 API但推荐使用 GREYActionBlock 创建自定义GREYAction在 block 中访问元素的任意字段或调用任意 selector。Objective-C 示例——在元素上调用自定义 selector// Objective-C - (void)testInvokeCustomSelectorOnElement { [[EarlGrey selectElementWithMatcher:grey_accessibilityID(id_of_element)] performAction:[GREYActionBlock actionWithName:Invoke clearStateForTest selector performBlock:^(id element, NSError *__strong *errorOrNil) { [element doSomething]; return YES; // Return YES for success, NO for failure. } ]]; }3.2 Swift 闭包中的“按引用传递”技巧同样的技术也适用于把元素属性提取到外部变量。Swift 3 的闭包中无法直接修改inout参数因此需要借助包装类强制实现“按引用传递”。以下示例把UILabel的文本属性提取到外部对象// Swift // // Must use a wrapper class to force pass by reference in Swift 3 closures. // inout params cannot be modified within closures. http://stackoverflow.com/a/28252105 open class Element { var text } /* * Example Usage: * * let element Element() * domainField.performAction(grey_replaceText(hello.there)) * .performAction(grey_getText(element)) * * GREYAssertTrue(element.text ! , reason: get text failed) */ public func grey_getText(_ elementCopy: Element) - GREYActionBlock { return GREYActionBlock.action(withName: get text, constraints: grey_respondsToSelector(#selector(getter: UILabel.text))) { element, errorOrNil - Bool in let elementObject element as? NSObject let text elementObject?.perform(#selector(getter: UILabel.text), with: nil)?.takeRetainedValue() as? String elementCopy.text text ?? return true } }从 GREYActionBlock.h 的实现看GREYActionBlock支持两种构造方式actionWithName:performBlock:和带constraints的actionWithName:constraints:performBlock:。GREYPerformBlock的返回值YES表示操作成功、NO表示失败当操作失败且未提供errorOrNil时会抛出NSException。3.3 在 Swift 中创建自定义 Action 的规范写法仓库功能测试 FTRSwiftTests.swift 中提供了完整示例创建一个检查元素是否隐藏的GREYActionBlock// Swift let checkHiddenBlock:GREYActionBlock GREYActionBlock.action(withName: checkHiddenBlock) { (element, errorOrNil) - Bool in // Check if the found element is hidden or not. let superView:UIView! element as! UIView return (superView.isHidden false) } ... EarlGrey().selectElementWithMatcher(grey_accessibilityLabel(label)) .performAction(checkHiddenBlock)对应的实际测试代码见 FTRSwiftTests.swift 中testInteractionWithALabelWithParentHidden方法。四、如何判断元素是否存在不抛出异常如果你不确定元素是否存在于 UI 层级中可以为交互传入NSError再检查错误域与错误码是否表明“元素未找到”// Objective-C NSError *error; [[EarlGrey selectElementWithMatcher:grey_accessibilityID(Foo)] assertWithMatcher:grey_notNil() error:error]; if ([error.domain isEqual:kGREYInteractionErrorDomain] error.code kGREYInteractionElementNotFoundErrorCode) { // Element doesn’t exist. }从源码看错误域与错误码的定义位于 GREYInteraction.hkGREYInteractionErrorDomain元素交互失败的错误域实际值定义在 GREYErrorConstants.m 中为com.google.earlgrey.ElementInteractionErrorDomainkGREYInteractionElementNotFoundErrorCode 0元素搜索失败。同一错误码还会在 GREYElementInteraction.m 中被用于断言、动作失败等场景。这种“传入 error 而非抛异常”的写法同样适用于performAction:error:与assert:error:更多用法可参考 api.md 的 Interaction APIs 章节。五、Splash Screen 与“等待元素出现”的标准做法5.1 用 GREYCondition 等待主界面App 带启动页Splash Screen时测试的setUp往往需要等待主屏出现。官方推荐使用 GREYCondition 等待主界面的根视图控制器// Objective-C - (void)setUp { [super setUp]; // Wait for the main view controller to become the root view controller. BOOL success [[GREYCondition conditionWithName:Wait for main root view controller block:^{ idUIApplicationDelegate appDelegate [UIApplication sharedApplication].delegate; UIViewController *rootViewController appDelegate.window.rootViewController; return [rootViewController isKindOfClass:[MainViewController class]]; }] waitWithTimeout:5]; GREYAssertTrue(success, Main view controller should appear within 5 seconds.); }从 GREYCondition.m 的实现可见GREYCondition底层借助GREYRunLoopSpinner驱动主线程 Run Loop 持续轮询条件 block直到条件满足或超时。需要特别注意的是两种等待方法的差异waitWithTimeout:等价于pollInterval:0在主线程上尽可能频繁地轮询CPU 开销很大除非需要条件一满足就立刻返回否则应优先使用带轮询间隔的版本waitWithTimeout:pollInterval:立即检查一次之后按指定的最小间隔轮询期间允许主线程休眠开销更小。源码中当interval 0时会通过CACurrentMediaTime()控制两次轮询之间的时间差。5.2 等待 UICollectionView 等视图填充完成作为同步不可行时的兜底方案同样用GREYCondition配合waitWithTimeout:pollInterval:等待元素出现。官方示例中明确提示pollInterval应大于 0避免过于频繁的层级扫描拖慢主线程。// Swift // Wait until 5 seconds for the view. let populated GREYCondition(name: Wait for UICollectionView to populate, block: { _ in var error: NSError? // Checking if collection view exists in the UI hierarchy. EarlGrey.selectElement(with:collectionViewMatcher) .assert(grey_notNil(), error: error) return error nil }).wait(withTimeout: 5.0, pollInterval: 0.5) GREYAssertTrue(populated, reason: Failed to populate UICollectionView in 5 seconds)// Objective-C GREYCondition *waitCondition [GREYCondition conditionWithName:Wait for UICollectionView to populate block:^BOOL { NSError *error; // Checking if collection view exists in the UI hierarchy. [[EarlGrey selectElementWithMatcher:collectionViewMatcher] assertWithMatcher:grey_notNil() error:error]; return error nil; }]; // Wait until 5 seconds for the view. BOOL populated [waitCondition waitWithTimeout:5.0 pollInterval:0.5]; GREYAssertTrue(populated, Failed to populate UICollectionView in 5 seconds);需要明确的是等待元素出现最佳方案仍是配置好同步机制让 EarlGrey 自动等待元素出现GREYCondition只是在同步无法生效时的备选方案。同步机制的具体内容见 features.md 的 Synchronization 章节。六、动画处理截断、加速与临时关闭同步EarlGrey 默认会截断超过阈值的 CALayer 动画相关配置定义在 GREYConfiguration.h。其中kGREYConfigKeyCALayerModifyAnimations默认值为YES开启后循环动画只运行一次且动画时长被限制在kGREYConfigKeyCALayerMaxAnimationDuration以内kGREYConfigKeyCALayerMaxAnimationDuration的默认值为10.0秒源码中的默认值见 GREYConfiguration.m 的init方法。6.1 调整最大动画时长// Swift let kMaxAnimationInterval:CFTimeInterval 5.0 GREYConfiguration.sharedInstance().setValue(kMaxAnimationInterval, forConfigKey: kGREYConfigKeyCALayerMaxAnimationDuration)// Objective-C [[GREYConfiguration sharedInstance] setValue:(kMaxAnimationInterval) forConfigKey:kGREYConfigKeyCALayerMaxAnimationDuration];6.2 加速动画除了截断动画还可以直接提高动画速度。UIKit 的 completion block 与异步调用仍会按原有逻辑执行只是更快这与真实运行条件下 iOS App 的表现一致能比“直接禁用动画”发现更多问题。需要注意的是加速对UIScrollView无效因为UIScrollView内部通过CADisplayLink驱动动画。// Swift GREYTestHelper.enableFastAnimation()// Objective-C [GREYTestHelper enableFastAnimation];查看 GREYTestHelper.m 的实现可以发现enableFastAnimation的本质是遍历所有UIWindow把window.layer的speed设置为 100disableFastAnimation则恢复为 1。6.3 临时关闭同步如果上述手段都不奏效可以临时禁用同步来跳过某个动画待动画结束后再重新开启。关闭同步的配置键是kGREYConfigKeySynchronizationEnabled默认值为YES// Swift GREYConfiguration.sharedInstance().setValue(false, forConfigKey: kGREYConfigKeySynchronizationEnabled)// Objective-C [[GREYConfiguration sharedInstance] setValue:NO forConfigKey:kGREYConfigKeySynchronizationEnabled];或者也可以在代码中用#if EARLGREY_ENV条件编译来“条件性禁用动画”配合第四节提到的 EarlGrey 构建配置。需要提醒的是kGREYConfigKeyCALayerModifyAnimations的注释中强调该开关只应在同步被禁用时使用否则循环动画会导致 EarlGrey 同步超时进而测试失败见 GREYConfiguration.h。6.4 屏幕“冻结 30 秒”与超时如果测试报超时错误通常是后台动画或同步 bug 让 App 一直处于忙碌状态——EarlGrey 默认会在 30 秒后对交互超时交互超时配置键kGREYConfigKeyInteractionTimeoutDuration默认值正是 30.0见 GREYConfiguration.h。如果测试能通过但只是慢则大概率是 matcher 在逐个检查每个元素此时应按下文“matcher 顺序”一节优化。七、元素匹配重复元素、匹配顺序与特殊层级7.1 元素在 App 中重复时如何匹配EarlGrey 要求 matcher 最终只匹配到唯一一个元素。当元素重复相同 label/class/位置时官方建议组合 matcher并追加grey_interactable()或grey_sufficientlyVisible()来收敛结果详见 api.md 的 EarlGrey Matchers 章节。7.2 matcher 顺序决定性能在grey_allOf(...)/grey_allOfMatchers([...])组合中顺序至关重要应从最具体最苛刻到最宽泛排列。推荐优先使用grey_accessibilityID或grey_accessibilityLabel它们能快速收敛候选元素。高效写法先按 ID 定位再检查可见性// Swift grey_allOfMatchers([grey_accessibilityID(Foo), grey_sufficientlyVisible()])// Objective-C grey_allOf(grey_accessibilityID(Foo), grey_sufficientlyVisible(), nil);先匹配到一个带目标 ID 的元素再对该元素检查可见性。如果顺序写反// Swift grey_allOfMatchers([grey_sufficientlyVisible(), grey_accessibilityID(Foo)])// Objective-C grey_allOf(grey_sufficientlyVisible(), grey_accessibilityID(Foo), nil);那么整个 App 的所有元素都会被做一次可见性检查最后才筛选出匹配 ID 的那个——明显更慢。相关 matcher 的实现位于 GREYMatchers.mgrey_accessibilityID、grey_sufficientlyVisible、grey_interactable、grey_kindOfClass、grey_notNil等均在此文件中。7.3 匹配内部 UIKit 类如果需要匹配无法直接引用的内部 UIKit 类使用NSClassFromString// Swift grey_kindOfClass(NSClassFromString(_UIAlertControllerView))grey_kindOfClass本身在 GREYMatchers.m 中实现接受一个Class参数运行时通过NSClassFromString拿到类对象即可作为其入参。7.4 匹配 AXN非无障碍元素EarlGrey 的视图层级输出中会用AXN标识非无障碍元素。Accessibility ID 既可以添加到无障碍元素也可以添加到非无障碍元素。当目标元素标记为AXN时以下基于无障碍属性的 matcher不会生效grey_accessibilityLabelgrey_accessibilityValuegrey_accessibilityTraitgrey_accessibilityHint如果AXN元素连grey_accessibilityID都无法匹配就必须改用非无障碍类 matcher如grey_kindOfClass、grey_text等来定位元素。7.5 屏幕外的元素先滚动再交互EarlGrey 要求元素**可见存在于 UI 层级中**才能执行自动化操作。正如真实用户会先滚动一样测试中应先通过 search action 把元素滚动到视野内。另外凡是要被交互例如grey_tap()的元素matcher 中必须包含grey_interactable()或grey_sufficientlyVisible()。否则 matcher 可能返回一个存在于层级但不可交互的元素tap 会因不满足 interactable 约束而失败。// Swift EarlGrey.selectElement(with:matcher) .using(searchAction: grey_scrollInDirection(GREYDirection.down, 200), onElementWithMatcher: grey_kindOfClass(UITableView.self)) .assert(grey_notNil())// Objective-C [[EarlGrey selectElementWithMatcher:matcher] usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 200) onElementWithMatcher:grey_kindOfClass([UITableView class]) assertWithMatcher:grey_notNil()];关于滚动方向枚举GREYDirection定义于 GREYConstants.h方向描述的是视口移动方向与手指移动方向相反例如手指上滑模拟“向下滚动页面”应使用kGREYDirectionDown。搜索动作的机制在 GREYInteraction.h 的usingSearchAction:onElementWithMatcher:注释中有详细说明该动作会重复执行直到目标元素被找到或超时。八、如何重置 App 状态、检测 EarlGrey 环境与调试视图层级8.1 在 setUp 中重置 App 状态推荐在 App Target 的 Build Settings 中将Defines Module设为Yes然后在 AppDelegate 上创建resetApplicationForTesting()方法。该方法应在setUp中调用而非tearDown否则无法保证第一个测试运行时 App 处于干净状态。Swift在 EarlGrey 测试 target 中用testable导入 App// Swift testable import App class MyTests: XCTestCase { override func setUp() { super.setUp() let appDelegate: AppDelegate UIApplication.shared.delegate as! AppDelegate appDelegate.resetApplicationForTesting() }Objective-C导入 App 的 app delegate 头文件// Objective-C #import MyAppDelegate.h interface MyTests : XCTestCase end implementation MyTests - (void)setUp { [super setUp]; MyAppDelegate *delegate (MyAppDelegate *)[[UIApplication sharedApplication] delegate]; [delegate resetApplicationForTesting]; }8.2 检测当前是否运行在 EarlGrey 环境两种方式方式一编译期检测。为 EarlGrey 创建独立的 build configuration例如定义EARLGREY_ENV宏然后条件编译// Objective-C #if EARLGREY_ENV ... #else ... #endif方式二运行时检测。检查 EarlGrey 核心类是否存在// Swift public static let envEarlGrey:Bool NSClassFromString(EarlGreyImpl) ! nilEarlGreyImpl是 EarlGrey 的入口实现类位于 EarlGreyImpl.m如果框架已注入运行时该类必然存在。8.3 通过 lldb 打印视图层级在任何测试中打断点然后在 Xcode 的 lldb 调试窗口粘贴 expression -- print(GREYElementHierarchy.hierarchyStringForAllUIWindows()) po [GREYElementHierarchy hierarchyStringForAllUIWindows]GREYElementHierarchy.h 提供了三个 APIhierarchyStringForElement:以指定元素为根、hierarchyStringForElement:withAnnotationDictionary:带注解字典可为元素附加特殊描述文本、hierarchyStringForAllUIWindows输出所有UIWindow的层级。这些输出即为调试元素匹配问题的第一手依据。8.4 其他测试辅助问答能否使用 Xcode Test Navigator可以。EarlGrey 开箱即用地支持Test Navigator。能否在测试中间设置断点可以。你可以为任意一次交互设置断点断点会在该交互执行之前被命中此时所有先前的交互均已执行完毕。XCTest bundle 在哪里以 Example 工程为例先运行一次EarlGreyExampleSwiftTeststarget然后找到cd ~/Library/Developer/Xcode/DerivedData/EarlGreyExample-*/Build/Products/Debug-iphonesimulator/EarlGreyExampleSwift.app/PlugIns/EarlGreyExampleSwiftTests.xctest/真机构建时把Debug-iphonesimulator替换为Debug-iphoneos。九、常见编译与配置问题9.1 Swift 工程中简写 matcher 全部报错在 CocoaPods 集成下Swift 工程偶尔会因 Source-Kit 问题找不到 EarlGrey 的 C 宏与Pods/目录的命名方式有关出现类似下图的编译错误应急方案依次为将Xcode 版本升级到最新FAQ 确认 Xcode 7.3.1 上不存在该问题若仍无效手动把 CocoaPods 的 EarlGrey 目录从Pods/EarlGrey/EarlGrey-1.0.0重命名为Pods/EarlGrey/EarlGrey完成后在 Project Navigator 中重新添加Pods/文件夹下的EarlGrey.framework文件并彻底删除 target Build Settings 中指向EarlGrey-1.0.0的所有 Framework Search Paths。9.2 Swift 字符串中的退格转义在 Swift 中退格backspace的转义字符是\u{8}。例如要输入 fooar先输入 foobar 再删除 b应写成grey_typeText(foob\u{8}ar)仓库功能测试 FTRSwiftTests.swift 的testTypingWithDeletion正是这样使用退格删除文本的。9.3 其他模态弹窗是否会导致测试失败会。如果这些弹窗属于运行测试的 App 进程且遮挡了测试正在交互的 UI 元素测试就会失败。这与 EarlGrey 基于截图差异比较screenshot diffs判定元素可见性的机制有关见 features.md 的 Visibility Checks 章节——被遮挡的元素不满足可见性要求。9.4 测试视频中 App 被缩放且带边框为了让 App 在测试视频中正确缩放请确保被测 App 为所有支持的设备提供了正确的启动屏Launch Screen图片资源。十、配置截图存储目录与其他全局配置10.1 修改截图等工件存放目录通过GREYConfiguration修改kGREYConfigKeyArtifactsDirLocation即可改变截图、测试日志等工件的存放位置// Objective-C [[GREYConfiguration sharedInstance] setValue:screenshot_dir_path forConfigKey:kGREYConfigKeyArtifactsDirLocation];查看 GREYConfiguration.m 可知该配置键的默认值被设为NSDocumentDirectory沙盒 Documents 目录。配置值必须是可写的绝对路径。GREYConfiguration是一个全局单例sharedInstance其内部维护默认配置与用户覆盖配置两份字典读取时先合并再取值调用reset可清除所有覆盖值、恢复默认setDefaultValue:forConfigKey:注册的自定义默认值不会被重置。10.2 其他常用配置键速查在 GREYConfiguration.h 中定义的全部配置键及默认值源码 GREYConfiguration.m 中确认汇总如下配置键接受值默认值作用kGREYConfigKeyAnalyticsEnabledBOOLYES是否开启框架使用统计kGREYConfigKeyActionConstraintsEnabledBOOLYES执行操作前是否做约束检查kGREYConfigKeyInteractionTimeoutDurationdouble非负30.0操作/断言的超时秒数kGREYConfigKeySynchronizationEnabledBOOLYES是否开启同步kGREYConfigKeyNSTimerMaxTrackableIntervaldouble非负1.5自动追踪的非重复 NSTimer 最大间隔kGREYConfigKeyDispatchAfterMaxTrackableDelaydouble非负1.5自动追踪的dispatch_after最大延迟kGREYConfigKeyDelayedPerformMaxTrackableDurationdouble非负1.5自动追踪的performSelector:afterDelay最大时长kGREYConfigKeyCALayerModifyAnimationsBOOLYES是否修改 CALayer 动画截断/单次运行kGREYConfigKeyCALayerMaxAnimationDurationdouble非负10.0CALayer 动画最大允许时长kGREYConfigKeyURLBlacklistRegexNSString 正则数组空数组不同步等待的 URL 黑名单正则kGREYConfigKeyIncludeStatusBarWindowBOOLNO截图与层级中是否包含状态栏窗口kGREYConfigKeyArtifactsDirLocation可写绝对路径nil实际默认 Documents截图等工件存放目录十一、针对预编译 App 运行测试Xcode 8 起新增两个 xcodebuild 命令build-for-testing生成.xctestrun文件供test-without-building使用test-without-building依据.xctestrun直接对预编译 App 运行测试。以下命令以 Demo/EarlGreyExample 工程为例详见man xcodebuild.xctestrun。先安装依赖$ cd Demo/EarlGreyExample $ pod install构建测试产物xcodebuild \ -workspace EarlGreyExample.xcworkspace \ -scheme EarlGreyExampleSwiftTests \ -destination platformiOS Simulator,nameiPhone 6,OSlatest \ -derivedDataPath xctestrun_dd \ build-for-testing不重新构建直接运行xcodebuild \ -workspace EarlGreyExample.xcworkspace \ -scheme EarlGreyExampleSwiftTests \ -destination platformiOS Simulator,nameiPhone 6,OSlatest \ -derivedDataPath xctestrun_dd \ test-without-building也可以直接指定 xctestrun 文件xcodebuild \ -xctestrun ./xctestrun_dd/Build/Intermediates/CodeCoverage/Products/EarlGreyExample_iphonesimulator10.0-x86_64.xctestrun \ -destination platformiOS Simulator,nameiPhone 6,OSlatest \ -derivedDataPath xctestrun_dd test-without-building十二、React Native 元素的支持情况EarlGrey 默认可以找到 React Native 中设置了accessibilityLabel的元素。总结如下默认所有可触摸元素touchable elements都是无障碍的设置了accessibilityLabel的按钮可以用grey_accessibilityLabel找到其他元素必须额外设置accessible: true否则按 label 查找不会命中支持testID属性的组件始终可以用grey_accessibilityID匹配即使该元素accessible: false。React Native 属性与原生 iOS/Android 概念的对应关系React Native 术语iOSAndroidaccessibilityLabelaccessibilityLabelcontent descriptiontestIDaccessibilityIDview tag组件侧推荐按以下方式设置测试属性// Set the test props of a component to enable UI testing function testLabel(description) { return { accessible: true, testID: description _id, accessibilityLabel: description _label } } Button onPress{(){}} titleautomation {...testLabel(automation_button)} / Image source{require(./img/image.png)} {...testLabel(automation_image)} /测试侧对应的 Swift 匹配写法// Swift EarlGrey.selectElement(with: grey_accessibilityLabel(automation_button_label)).assert(grey_sufficientlyVisible()); EarlGrey.selectElement(with: grey_accessibilityLabel(automation_image_label)).assert(grey_sufficientlyVisible()); EarlGrey.selectElement(with: grey_accessibilityID(automation_image_id)).assert(grey_sufficientlyVisible());十三、延伸阅读FAQ 之外官方文档体系还提供了更系统的参考api.mdEarlGrey 的 Interaction、Synchronization 与其他顶层 API 全览features.md同步、可见性检查、用户仿真交互等核心特性install-and-run.mdCocoaPods、Carthage 与手动三种安装方式及首个测试的编写known-issues.md已知问题清单README.md项目总览与入门路径。需要说明的是当前仓库对应 EarlGrey 1.x 系列README 已标注 EarlGrey 1.0 已被集成 XCUITest 的 EarlGrey 2.0 取代文中涉及的 API、配置键与默认值均以本仓库 EarlGrey/ 目录下的实际源码为准在集成时请核对你所使用版本的兼容性说明见 versions.md。赞分享测试【免费下载链接】EarlGrey:tea: iOS UI Automation Test Framework项目地址https://gitcode.com/gh_mirrors/ea/EarlGrey点击查看免费下载相关推荐Hermes WebUI个人助理日常生活与工作的智能帮手Hermes WebUI个人助理日常生活与工作的智能帮手 Hermes WebUI是一款功能强大的个人助理工具通过网页或手机即可轻松使用Hermes Age人工智能AI 应用AI Agent交互助手MCP 服务前端AFL 常见问题FAQ权威指南灰盒模糊测试原理、性能调优与故障排查实战AFL 常见问题FAQ权威指南灰盒模糊测试原理、性能调优与故障排查实战 导读 本文以 AFL 官方 FAQ docs/FAQ.md https应用安全测试漏洞扫描electron-tabs常见问题解答解决90%开发者遇到的集成难题electron tabs常见问题解答解决90%开发者遇到的集成难题 Electron tabs是一个简单易用的Electron标签页组件为Electron前端UI组件桌面应用上一篇【免费下载】 Markdown All in One 使用教程下一篇OWASP Nettacker 安装与使用教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考