iOS自动化测试的那些干货

发表于:2017-9-04 15:38

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:Cocoachina    来源:51Testing软件测试网采编

  前言
  如果有测试大佬发现内容不对,欢迎指正,我会及时修改。
  大多数的iOS App(没有持续集成)迭代流程是这样的
  也就是说,测试是发布之前的最后一道关卡。如果bug不能在测试中发现,那么bug就会抵达用户,所以测试的完整性和可靠性十分重要。
  目前,大多数App还停留在人工测试阶段,人工测试投入的成本最低,能够保证核心功能的使用,而且测试人员不需要会写代码。
  但是,在很多测试场景下,人工测试的效率太低,容易出错。举两个常见的例子:
  一个App的核心功能,在每一次发布版本前的测试必定会跑一遍所有的测试用例,不管对应的业务在当前版本有没有变化(天知道开发在做业务A的时候,对业务B有没有影响),如果这次测出新的bug,测试人员在下一次发版测试中,又不得不做这些重复的工作
  开发在写API请求相关代码的时候没有做数据容错,测试在人工测试的时候都是正常的数据,所以测试通过。上线了之后,后台配置数据的时候出了点小问题,导致大面积崩溃,boom~。
  然后,老板就要过来找你了
  本文所讲解的均是基于XCode 8.2.1,有些概念可能不适用于低版本的XCode
  自动化测试
  自动化测试就是写一些测试代码,用代码代替人工去完成模块和业务的测试。
  其实不管是开发还是测试,如果你在不断的做重复性工作的时候,就应该问自己一个问题:是不是有更高效的办法?
  自动化测试有很多优点:
  测试速度快,避免重复性的工作
  避免regression,让开发更有信心去修改和重构代码(个人认为最大的优点)
  具有一致性。
  有了自动化测试,持续集成(CI)会变得更可靠。
  迫使开发人员写出更高质量的代码。(自动化测试不通过,代码不允许合并)
  当然,自动化测试也有一些缺点。
  开发和维护成本高。
  不能完全替代人工测试。
  无法完全保证测试的准确性 - 让代码去判断一段逻辑是否正确很容易,但是,让代码判断一个控件显示是否正确却没那么容易。
  所以,在做自动化测试之前,首先要问自己几个问题?
  这个测试业务的变动是否频繁?
  这个测试业务是否属于核心功能?
  编写测试代码的成本有多少?
  自动化测试能保证测试结果的准确么?
  通常,我们会选择那些业务稳定,需要频繁测试的部分来编写自动化测试脚本,其余的采用人工测试,人工测试仍然是iOS App开发中不可缺少的一部分。
  测试种类
  从是否接触源代码的角度来分类:测试分为黑盒和白盒(灰盒就是黑盒白盒结合,这里不做讨论)。
  白盒测试的时候,测试人员是可以直接接触待测试App的源代码的。白盒测试更多的是单元测试,测试人员针对各个单元进行各种可能的输入分析,然后测试其输出。白盒测试的测试代码通常由iOS开发编写。
  黑盒测试。黑盒测试的时候,测试人员不需要接触源代码。是从App层面对其行为以及UI的正确性进行验证,黑盒测试由iOS测试完成。
  从业务的层次上来说,测试金字塔如图:
  而iOS测试通常只有以下两个层次:
  Unit,单元测试,保证每一个类能够正常工作
  UI,UI测试,也叫做集成测试,从业务层的角度保证各个业务可以正常工作。
  框架选择
  啰里八嗦讲的这么多,自动化测试的效率怎么样,关键还是在测试框架上。那么,如何选择测试框架呢?框架可以分为两大类:XCode内置的和三方库。
  选择框架的时候有几个方面要考虑
  ●测试代码编写的成本
  ●是否可调式
  ●框架的稳定性
  ●测试报告(截图,代码覆盖率,…)
  ●WebView的支持(很多App都用到了H5)
  ●自定义控件的测试
  ●是否需要源代码
  ●能否需要连着电脑
  ●是否支持CI(持续集成)
  …
  我们首先来看看XCode内置的框架:XCTest。XCTest又可以分为两部分:Unit Test 和 UI Test,分别对应单元测试和UI测试。有一些三方的测试库也是基于XCTest框架的,这个在后文会讲到。由于是Apple官方提供的,所以这个框架会不断完善。
  成熟的三方框架通常提供了很多封装好的有好的接口,笔者综合对比了一些,推荐以下框架:
  单元测试:
  以下三个框架都是BDD(Behavior-driven development) - 行为驱动开发。行为驱动开发简单来说就是先定义行为,然后定义测试用例,接着再编写代码。 实践中发现,通常没有那么多时间来先定义行为,不过BDD中的domain-specific language (DSL)能够很好的描述用例的行为。
  Kiwi 老牌测试框架
  specta 另一个BDD优秀框架
  Quick 三个项目中Star最多,支持OC和Swift,优先推荐。
  UI测试
  KIF 基于XCTest的测试框架,调用私有API来控制UI,测试用例用Objective C或Swift编写。
  appium 基于Client - Server的测试框架。App相当于一个Server,测试代码相当于Client,通过发送JSON来操作APP,测试语言可以是任意的,支持android和iOS。
  篇幅有限,本文会先介绍XCtest,接着三方的Unit框架会以Quick为例,UI Test框架侧重分析KIF,appium仅仅做原理讲解。
  XCTest
  对于XCTest来说,最后生成的是一个bundle。bundle是不能直接执行的,必须依赖于一个宿主进程。关于XCTest进行单元测试的基础(XCode的使用,异步测试,性能测试,代码覆盖率等),我在这篇文章里讲解过,这里不再详细讲解。
  iOS 单元测试之XCTest详解
  单元测试用例
  比如,我有以下一个函数:
  //验证一段Text是否有效。(不能以空字符开头,不能为空)
  - (BOOL)validText:(NSString *)text error:(NSError *__autoreleasing *)error{
  }
  那么,我该如何为这个函数编写单元测试的代码?通常,需要考虑以下用例:
  输入以空白字符或者换行符开头的,error不为空,返回 NO
  输入正确的内容,error为空,返回YES
  输入为nil,error不为空,返回 NO (边界条件)
  输入为非NSString类型,验证不通过,返回NO (错误输入)
  特殊输入字符(标点符号,非英文等等)
  UI测试
  UI测试是模拟用户操作,进而从业务处层面测试。关于XCTest的UI测试,建议看看WWDC 2015的这个视频:
  UI Testing in Xcode
  关于UI测试,有几个核心类需要掌握
  XCUIApplication 测试应用的代理
  XCUIElement 一个UI上可见的视图对象
  XCUIElementQuery 查找XCUIElement
  UI测试还有一个核心功能是UI Recording。选中一个UI测试用例,然后点击图中的小红点既可以开始UI Recoding。你会发现:
  随着点击模拟器,自动合成了测试代码。(通常自动合成代码后,还需要手动的去调整)
  在写UI测试用例的时候要注意:测试行为而不是测试代码。比如,我们测试这样一个case
  进入Todo首页,点击add,进入添加页面,输入文字,点击save。
  测试效果如下:
  对应测试代码:
  - (void)testAddNewItems{
  //获取app代理
  XCUIApplication *app = [[XCUIApplication alloc] init];
  //找到第一个tabeview,就是我们想要的tableview
  XCUIElement * table = [app.tables elementBoundByIndex:0];
  //记录下来添加之前的数量
  NSInteger oldCount = table.cells.count;
  //点击Add
  [app.navigationBars[@"ToDo"].buttons[@"Add"] tap];
  //找到Textfield
  XCUIElement *inputWhatYouWantTodoTextField = app.textFields[@"Input what you want todo"];
  //点击Textfield
  [inputWhatYouWantTodoTextField tap];
  //输入字符
  [inputWhatYouWantTodoTextField typeText:@"somethingtodo"];
  //点击保存
  [app.navigationBars[@"Add"].buttons[@"Save"] tap];
  //获取当前的数量
  NSInteger newCount = table.cells.count;
  //如果cells的数量加一,则认为测试成功
  XCTAssert(newCount == oldCount + 1);
  }
  这里是通过前后tableview的row数量来断言成功或者失败。
  等待
  通常,在视图切换的时候有转场动画,我们需要等待动画结束,然后才能继续,否则query的时候很可能找不到我们想要的控件。
  比如,如下代码等待VC转场结束,当query只有一个table的时候,才继续执行后续的代码。
  [self expectationForPredicate:[NSPredicate predicateWithFormat:@"self.count = 1"]
  evaluatedWithObject:app.tables
  handler:nil];
  [self waitForExpectationsWithTimeout:2.0 handler:nil];
  //后续代码....
  Tips: 当你的UI结构比较复杂的时候,比如各种嵌套childViewController,使用XCUIElementQuery的代码会很长,也不好维护。
  另外,UI测试还会在每一步操作的时候截图,方便对测试报告进行验证。
  查看测试结果
  使用基于XCTest的框架,可以在XCode的report navigator中查看测试结果。
  其中:
  ●Tests 用来查看详细的测试过程
  ●Coverage 用来查看代码覆盖率
  ●Logs 用来查看测试的日志
  点击图中的红色框指向的图标可以看到每一步UI操作的截图
  除了利用XCode的GUI,还可以通过后文提到的命令行工具来测试,查看结果。
  Stub/Mock
  首先解释两个术语:
  ●mock 表示一个模拟对象
  ●stub 追踪方法的调用,在方法调用的时候返回指定的值。
  通常,如果你采用纯存的XCTest,推荐采用OCMock来实现mock和stub,单元测试的三方库通常已集成了stub和mock。
  那么,如何使用mock呢?举个官方的例子:
  //mock一个NSUserDefaults对象
  id userDefaultsMock = OCMClassMock( [NSUserDefaults class]);
  //在调用stringForKey的时候,返回http://testurl
  OCMStub([userDefaultsMock 
  stringForKey:@"MyAppURLKey"] ).andReturn( @"http://testurl");
  再比如,我们要测试打开其他App,那么如何判断确实打开了其他App呢?
  id app = OCMClassMock([UIApplication class]);
  OCMStub([app sharedInstance]).andReturn(app);
  OCMVerify([app openURL:url]
  使用Stub可以让我们很方便的实现这个。
  关于OCMock的使用,推荐看看objc.io的这篇文章
  置换测试: Mock, Stub 和其他

21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号