基于Xcode 7.1的UI Testing初探

写在前面

iOS 里面大致有两种测试的方法,系统的UNIT测试,以及UIAutomation插件的方法。以前只是有听说,笔者并未过多关注这些方面的东西,13年开始接触这个行业的时候就有看到单元测试,只是不了解,主要在学习基础部分。上班两年多了,随着项目的日积月累,测试已经是一件必须提上日程的事情。但是介于不动脑子以及项目的紧迫性,大部分功能都是实现即可,不考虑性能问题,以至于现在想要做测试也是分外的困难。

目前看到如下几个问题:

  • 项目负载过大;
  • 代码的冗余度过高;
  • 代码的耦合度过高;

经分析:

  • 项目负载大,就意味着出现错误的可能性更多,也就意味着Assert的代码更多,我面对这个项目的时候,不知道该从何着手。

  • 冗余度高,前期在做这个项目的时候,只想着实现功能,别让领导以为自己真的不行,就忽略了已有框架里面封装的方法,直接采用网上的方法或者处理手段,比如,获取view的图片的方法,自己费了好大的劲儿写完之后才发现,H领导已经封装了imageForView的方法,尴尬😅。

  • 代码耦合度高,一个类里面定义公开的property,在其他方法里面并未直接以参数的形式传入,而是直接调用,造成测试时无法mock假的数据,类与类之间过渡依赖。

所以,晓得吗?我感觉自己啥都不会了,不晓得怎么去做这个测试,根本没有入手点,H领导们和别的同事一起封闭开发去了,剩下我独自啃着啃不动的干粮,哭毙了。。。

UI Testing 是Xcode 7开始,Apple 对外公布的用于界面测试的方法,貌似这个一直都存在的,之前一直在内部使用,现在公开出来。该技术主要根据通过界面元素,审查app的运行是否正确。

UI Testing的结构

  • XCUIApplication, 有点儿类似于Obecjtive 里面的UIApplication,继承于XCUIElement;
  • XCUIElementQuery,查询试图之间的关联;
  • XCUIElement,界面的可视化的元素,可以通过设置AccesibilityIdentifier访问,若是没有设置,可通过设置的值label,value,title唯一标示访问;

    界面部分,可以通过某个元素是否存在来检测,利用XCUIElement的exists属性。

期望判断

XCUITests提供了用于判断是否达到预期效果的方法;

1
2
3
4
5
#if XCT_NULLABLE_AVAILABLE
- (XCTestExpectation *)expectationForNotification:(NSString *)notificationName object:(nullable id)objectToObserve handler:(nullable XCNotificationExpectationHandler)handler;
#else
- (XCTestExpectation *)expectationForNotification:(NSString *)notificationName object:(id)objectToObserve handler:(XCNotificationExpectationHandler)handler;
#endif

可以设计预订的时间等待某个通知是否能接受,接受到notify,则继续执行,等待不到,则直接崩溃,抛出异常信息。

比如,我在2秒钟以后发送通知,主线程直接进入等待状态:

1
2
3
4
5
6
7
8
 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter]postNotificationName:stateName object:nil];
};

do {
[self expectationForNotification:stateName object:nil handler:nil];
[self waitForExpectationsWithTimeout:second handler:nil];
} while (0);

以上这段代码,会在2秒钟以后正常执行,若是碰不到本地的通知,则底下超出second时间,将会崩溃。

  • 这里有一个细节的东西要特别注意,waitForExpectationsWithTimeout:这个方法必须是在测试的主线程执行的,若是在其他线程,则程序会崩溃,提示这个方法必须在主线程执行,这句代码以后的代码,若等待到notify,则会在sencond以后正常执行。

话外之语

以前都不知道为啥H领导要这样那样的分成零散的方法去处理一段逻辑,那时的我看代码都是不停的跳转,觉得这样单独的功能分裂多块去处理,代码不严谨,但是现在我觉得,H领导很有前瞻性,这种构架对于后期开发一场有效。

其他相关文章如下:

其他测试

其他测试方案如下: