作者:时-_尚微视点 | 来源:互联网 | 2023-07-23 19:10
iOS模拟器发送通知和UI测试
背景 我们可能通过点击通知直接跳转到页面指定页面,或者点击通知打开web页面,更或者通过其他应用启动 app打开指定页面。面对这种跳转指定页面我们应该如何做 UI测试了?
向模拟器发送通知 从 Xcode11.4中,用户可以想 iOS 模拟器推送通知,包含以下两种方式:
终端使用 Xcode 命令执行,发送通知。 将 apns 文件拖放到目标模拟器。 apns 文件 首先我们需要定义 apns 发送文件,并命名ExamplePush.apns
。
定义格式如下:
{ "Simulator Target Bundle" : "xxxx(包名)" , "aps" : { "badge" : 0 , "alert" : { "title" : "打开百度" , "subtitle" : "url加载测试" , "body" : "点击跳转App web 容器并且打开百度搜索" , } , "sound" : "default" , } , "route" : { "url" : "https://www.baidu.com/" } }
至此,你可以填写正确的应用包名,通过拖拽到模拟器来发送通知了。
Xcode 命令发送 在项目已经正确配置好通知所需要的条件后,保证待测模拟器的通知权限已经开启。
发送命令如下:
xcrun simctl push < device> com.example.my-app ExamplePush.apns
如命令所见,我们需要模拟器标识符,应用包名和 apns 文件。
同理,我们还可以通过xcrun simctl openurl booted
来发送通用链接和 scheme 跳转,请参考文章IOS Deep linking: URL Scheme vs Universal Links
获取模拟器设备标识符
应用包名
在结合之前我们定义的 apns 文件,发送通知的命令如下:
xcrun simctl push 942A6B1C-BE29-4E05-A075-5146088F7C9E com.compass.MusselExample PushNotificationTest.apns
UI 测试发送通知 可惜的是 XCodeTest 并没有提供在测试中发送通知的方式。
接下来该怎么办了?
方法1:【推荐】借助其他库实现,比如Mussel(可以在测试用例中发送通知、Scheme Link 和通用链接,最低支持 iOS11)、NWPush(配置麻烦,需要各种证书,教程示例)等库
方法2:自己写 shell 脚本和命令
使用 Mussel 发送通知 Mussel github 仓库:https://github.com/UrbanCompass/Mussel
自定义脚本发送通知 原理:在编译 UI测试 target 期间,添加运行脚本来发送通知
缺点:每次编译都会发送通知(需要手动控制参数)
编写推送通知脚本 #!/bin/bash isAllowPushNotification = 1 DIR = "$( cd "$( dirname "$0 " ) " && pwd ) " echo ${DIR} pushNotification ( ) { diviceId = xxxxxappName = xxxxxcrun simctl push $diviceId $appName ./ExamplePush.apns} if [ $isAllowPushNotification == 1 ] ; then pushNotificationfi
暂且命名为 pushNotification.sh 并把相应的权限修改了chmod +x pushNotification.s
(不然没有执行权限)。
为 UITest 添加运行脚本 将所需的脚本和 apns 文件都添加到测试 target 目录下后,选中UI 测试 target。 添加脚本。
这样每次编译 UI 测试 target 就会发送通知了。
打开通知页面的测试操作 注意:我这里为了方便测试,关闭了通知以组显示的方式。
参数和setUp 方法
@interface OpentNotificationUITests : XCTestCase @property(nonatomic, strong) XCUIApplication *app; //当前应用 @property(nonatomic, strong) XCUIApplication *springboard; //系统页面 @end@implementation OpentNotificationUITests- (void)setUp {// Put setup code here. This method is called before the invocation of each test method in the class.// In UI tests it is usually best to stop immediately when a failure occurs.self.cOntinueAfterFailure= NO;// UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.self.app = [[XCUIApplication alloc] init];self.springboard = [[XCUIApplication alloc] initWithBundleIdentifier:@"com.apple.springboard"];[self.app launch];// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. }
测试方法
- (void)testOpenUrlFromNotification{[self openNotificationCenterTitle:@"打开百度"];NSArray *webViews = [[self.app webViews] allElementsBoundByIndex]; //业务中已处理(点击会通过 webViewController 去加载 url)XCTAssertTrue((webViews.count >= 1), @"应该打开 web 页面"); // 或者使用XCTAssertTrue([webViews[0] waitForExistenceWithTimeout:10], @"应该打开 web 页面"); }
辅助方法
我这里是通过通知的标题来获取对应通知,然后进行点击打开。
#pragma mark - helper /// 相当于按 Home 键 - (void)toHome{[[XCUIDevice sharedDevice] pressButton:XCUIDeviceButtonHome]; } /// 打开通知, 注意 需要保证模拟器通知方式[取消以组显示通知],通知 title 也需要不一致。 - (void)openNotificationCenterTitle:(NSString * _Nonnull)title {[self toHome];XCUIApplication *app = self.springboard;XCUICoordinate *coord1 = [app coordinateWithNormalizedOffset:CGVectorMake(0.1, 0.01)];XCUICoordinate *coord2 = [app coordinateWithNormalizedOffset:CGVectorMake(0.1, 0.8)];[coord1 pressForDuration:0.1 thenDragToCoordinate:coord2]; // 滑动显示通知XCUIElement *mainWindow = [[app windows] elementMatchingType:XCUIElementTypeWindow identifier:@"SBCoverSheetWindow"];NSArray *notiCells = [[mainWindow scrollViews] allElementsBoundByIndex];XCUIElement *scroll = notiCells[0];NSArray *allNotiCells = [[scroll scrollViews] allElementsBoundByIndex];XCUIElement *aimElement = nil;for (int i=0; i }
消息点击效果