EarlGrey - iOS UI自动化测试框架
项目标题与描述
EarlGrey是由Google开发的iOS原生UI自动化测试框架,支持Objective-C和Swift语言。它是一个白盒测试解决方案,深度集成XCTest框架,可直接在Xcode的Test Navigator中运行测试。
核心价值:
- 自动同步UI状态、网络请求和各种队列
- 提供丰富的交互API和断言功能
- 支持编写清晰简洁的测试代码
- 与Xcode完美集成,可直接从IDE运行测试
注意:EarlGrey 1.0已停止维护,推荐使用集成XCUITest的EarlGrey 2.0
功能特性
核心功能
- 智能同步机制:自动等待UI进入稳定状态
- 丰富的交互API:点击、滑动、长按等手势操作
- 元素定位器:多种方式定位UI元素(Accessibility ID、文本等)
- 断言验证:丰富的断言方法验证UI状态
- WebView支持:可测试嵌入的Web内容
- 多手势支持:支持多指滑动手势
独特价值
- 稳定性保障:内置同步机制减少测试 flakes
- 精确控制:可自定义手势参数(持续时间、方向等)
- 调试友好:失败时自动记录视图层次结构
- 扩展性强:支持自定义匹配器和动作
安装指南
CocoaPods安装
- 安装EarlGrey gem:
gem install earlgrey
- 在项目目录下运行:
pod install
- 打开生成的xcworkspace文件
Carthage安装
- 安装依赖工具:
brew install carthage xcode-select --install gem install earlgrey
- 初始化EarlGrey:
earlgrey install --carthage --swift-version=3.0 --target=EarlGreyExampleSwiftTests carthage update EarlGrey --platform ios
系统要求
- Xcode 10.0+
- iOS 9.0+
- CocoaPods 1.0.0+
使用说明
基础测试示例
// 选择并点击按钮
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"ClickMe")]
performAction:grey_tap()];
// 验证标签文本
[[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"textLabel")]
assertWithMatcher:grey_text(@"Expected Text")];
滑动操作
// 向下滑动50点
[[EarlGrey selectElementWithMatcher:grey_kindOfClass([UIScrollView class])]
performAction:grey_scrollInDirection(kGREYDirectionDown, 50)];
高级功能
// 自定义长按手势(持续2秒)
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"LongPressArea")]
performAction:grey_longPressWithDuration(2.0)];
// 多指滑动手势(3指同时滑动)
GREYMultiFingerSwipeAction *swipe =
[[GREYMultiFingerSwipeAction alloc] initWithDirection:kGREYDirectionUp
duration:1.0
numberOfFingers:3];
[[EarlGrey selectElementWithMatcher:grey_anyOf(grey_kindOfClass([UIView class]), nil)]
performAction:swipe];
核心代码
基础交互实现
// GREYTapAction.m 点击动作实现
- (BOOL)perform:(id)element error:(__strong NSError **)errorOrNil {
if (![self satisfiesConstraintsForElement:element error:errorOrNil]) {
return NO;
}
UIView *viewToTap = [element isKindOfClass:[UIView class]] ?
element : [element grey_viewContainingSelf];
UIWindow *window = [viewToTap isKindOfClass:[UIWindow class]] ?
(UIWindow *)viewToTap : viewToTap.window;
return [GREYTapper tapOnWindow:window
numberOfTaps:_numberOfTaps
location:[self grey_tapPointForElement:element]
error:errorOrNil];
}
同步机制实现
// GREYUIThreadExecutor.m 主线程同步
- (void)executeSync:(GREYExecutionBlock)block {
if ([NSThread isMainThread]) {
block();
} else {
dispatch_semaphore_t waitForBlock = dispatch_semaphore_create(0);
dispatch_async(dispatch_get_main_queue(), ^{
block();
dispatch_semaphore_signal(waitForBlock);
});
dispatch_semaphore_wait(waitForBlock, DISPATCH_TIME_FOREVER);
}
}
元素定位实现
// GREYElementMatcher.m 元素匹配逻辑
- (BOOL)matches:(id)item {
if (![self checkClassAndVisibility:item]) {
return NO;
}
for (id<GREYMatcher> matcher in _matchers) {
if (![matcher matches:item]) {
return NO;
}
}
return YES;
}
更多精彩内容 请关注我的个人公众号 公众号(办公AI智能小助手)
公众号二维码