☰
EarlGrey iOS UI 自动化测试 FAQ 实战指南:从白盒原理到常见问题排查
2026/10/12 3:01:43 网站建设 项目流程
  • 测试

【免费下载链接】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。排查思路:

  1. 构建 Test Target,检查被测 App Bundle 中是否存在框架。对于名为MyApp的 App,EarlGrey.framework应位于MyApp.app/EarlGrey.framework。
  2. 如果不存在,确认 Test Target 的Build Phases中配置了Copy to $(TEST_HOST)脚本,将框架拷贝到 App Bundle 内。配置方法见 install-and-run.md。
  3. 重新构建后再检查;若框架仍不在 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.h:

  • kGREYInteractionErrorDomain:元素交互失败的错误域,实际值定义在 GREYErrorConstants.m 中,为com.google.earlgrey.ElementInteractionErrorDomain;
  • kGREYInteractionElementNotFoundErrorCode = 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:^{ id<UIApplicationDelegate> 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设置为 100(disableFastAnimation则恢复为 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.m(grey_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 匹配 AX=N(非无障碍)元素

EarlGrey 的视图层级输出中,会用AX=N标识非无障碍元素。Accessibility ID 既可以添加到无障碍元素,也可以添加到非无障碍元素。当目标元素标记为AX=N时,以下基于无障碍属性的 matcher不会生效:

  • grey_accessibilityLabel
  • grey_accessibilityValue
  • grey_accessibilityTrait
  • grey_accessibilityHint

如果AX=N元素连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") != nil

EarlGreyImpl是 EarlGrey 的入口实现类,位于 EarlGreyImpl.m,如果框架已注入运行时,该类必然存在。

8.3 通过 lldb 打印视图层级

在任何测试中打断点,然后在 Xcode 的 lldb 调试窗口粘贴:

> expression -- print(GREYElementHierarchy.hierarchyStringForAllUIWindows())
> po [GREYElementHierarchy hierarchyStringForAllUIWindows]

GREYElementHierarchy.h 提供了三个 API:hierarchyStringForElement:(以指定元素为根)、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/目录的命名方式有关),出现类似下图的编译错误:

应急方案依次为:

  1. 将Xcode 版本升级到最新(FAQ 确认 Xcode 7.3.1 上不存在该问题);
  2. 若仍无效,手动把 CocoaPods 的 EarlGrey 目录从Pods/EarlGrey/EarlGrey-1.0.0重命名为Pods/EarlGrey/EarlGrey;
  3. 完成后,在 Project Navigator 中重新添加Pods/文件夹下的EarlGrey.framework文件;
  4. 并彻底删除 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 'platform=iOS Simulator,name=iPhone 6,OS=latest' \ -derivedDataPath 'xctestrun_dd' \ build-for-testing

不重新构建直接运行:

xcodebuild \ -workspace EarlGreyExample.xcworkspace \ -scheme EarlGreyExampleSwiftTests \ -destination 'platform=iOS Simulator,name=iPhone 6,OS=latest' \ -derivedDataPath 'xctestrun_dd' \ test-without-building

也可以直接指定 xctestrun 文件:

xcodebuild \ -xctestrun './xctestrun_dd/Build/Intermediates/CodeCoverage/Products/EarlGreyExample_iphonesimulator10.0-x86_64.xctestrun' \ -destination 'platform=iOS Simulator,name=iPhone 6,OS=latest' \ -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 术语iOSAndroid
accessibilityLabelaccessibilityLabelcontent description
testIDaccessibilityIDview 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={()=>{}} title="automation" {...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.md:EarlGrey 的 Interaction、Synchronization 与其他顶层 API 全览;
  • features.md:同步、可见性检查、用户仿真交互等核心特性;
  • install-and-run.md:CocoaPods、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
点击查看免费下载

相关推荐

上一篇:【免费下载】 Markdown All in One 使用教程
下一篇:OWASP Nettacker 安装与使用教程

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询