iOS单元测试详解

发表于:2018-2-02 10:22

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

 作者:赵先生Try    来源:简书

  简介
  测试目的:模拟多种可能性,减少错误,增强健壮性,提高稳定性。
  测试种类:在iOS中的通常分为单元测试和UI测试。
  单元测试(Unit Test):用来保证每一个类正常工作。
  UI测试(UI Test):从业务层的角度保证各个业务可以正常工作。
  测试框架:除了XCode自带的测试框架XCTest,还有以下列出的三方框架。
  XCTest:同时支持单元测试和UI测试。
  单元测试:
  - 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及Xcode工具进行单元测试,编写测试代码,以及如何让你的代码更容易单元测试(可能是重构代码的不归路)。
  XCTest测试
  1. 测试基础
  ●测试就是的您编写的测试代码,可以执行您的应用程序和库代码,根据一系列期望进行判断(使用断言XCTAssert),导致通过或失败的结果。对于性能测量测试,参考标准可能是期望一组代码运行到完成的最长时间。
  ●所有软件都是使用组合构建的;也就是说,较小的组件被布置在一起以形成具有更大功能的更大,更高级别的组件,直到满足项目的目标和要求。良好的测试实践是进行测试,涵盖此组合的各个层次的功能。 XCTest允许您为任何级别的组件编写测试。您可以定义什么构成组件进行测试 - 它可以是一个类中的方法或一组完成重要目的的方法。测试组件的行为应该是完全确定的;测试通过或失败。
  ●项目组件的测试设计的基础是测试驱动开发,它是编写代码的一种风格,您可以在编写被测试代码之前编写测试逻辑。这种开发方法使您可以在实现代码之前对需求和边缘案例进行整理编写。编写测试后,您将开发您的被测试代码,目的是通过测试。 当您修复错误时,您将添加确认错误已修复的测试。
  ●性能测试
  XCTest提供API来测量基于时间的性能,测试必须有一个评估基准, 评估基准是测试方法的十次运行中的平均时间与每次运行的标准偏差的组合。 低于评估基准或从运行到运行的变化太大的测试报告为失败,否则就是成功。
  注意:首次执行性能测量测试时,XCTest始终报告失败,因为未设置评估基准。
  ●UI测试:模拟用户操作,进而从业务层面测试。
  UI测试的工作原理是通过查询应用程序的UI对象,合成事件并将其发送到这些对象,并提供丰富的api,使您能够检查UI对象的属性和状态,将其与预期状态进行比较。UI测试使您能够查找应用程序的UI并与其进行交互,以验证UI元素的属性和状态。
  UI测试包括UI录制,是帮助你快速编写UI测试的好方法。
  ●应用程序和库测试
  应用程序测试:测试检查应用程序中代码的正确行为,例如计算器应用程序的算术运算示例。
  库测试:检查动态库和框架中代码的正确行为,而不管它们在应用程序的运行时间中的使用情况。 你可以创建单元测试去构建库测试。
  2. 测试从哪开始
  ●在创建单元测试时,专注于测试您的代码的最基本的基础,Model类和与Controller进行交互的方法。你的应用程序中很有可能有Model,View,Controller这些类,首先编写测试来覆盖所有的Model类时,确定Model或者更基础的类是经过很好的测试,然后再开始为Controller类编写测试,这些测试开始接触应用程序的复杂部分,例如,连接到网络。
  ●在创建UI测试时,首先考虑最常见的工作流程。想想用户在开始使用应用程序时使用什么以及在该过程中立即执行什么。使用UI录制功能是将用户操作序列捕获到UI测试方法中的好方法。
  3. 新建测试Target 及 测试类
  ●新建工程选择单元测试和UI测试
  step1. 新建工程选择单元测试和UI测试
  左侧Project navigation区和右侧Project editor区中对应新建项目中的单元测试和UI测试的资源。
  step2. Project navigation & Project editor
  新建的测试Target默认包含一个测试类,这个类是XCTestCase的子类,且这个类只有.m文件。
  step3.
  ●选择Project editor新建测试
  step1. Project editor中新建单元测试
  选择需要测试的Target,新建单元测试
  step2. 选择需要测试的Target
  选择Test navigation新建测试,在这里可以选择新建测试Target 或者测试类。你可以根据你的意愿新建任意多个测试Target,每个测试Target下可以新建任意多个测试类。
  step1.Test navigation新建测试或者测试类
  Test navigation中分层显示出项目中包含的测试Target,测试类,以及测试方法。
  Test navigation
  4. 编写测试方法
  测试方法是以前缀test开头的测试类的实例方法,不需要参数,返回void,例如-(void)testExample()。测试方法在您的项目中执行代码,使用XCTest框架提供的断言来呈现Xcode显示的测试结果。如果该代码不产生预期结果,则使用一组断言(XCTAssert)API报告失败。例如,函数的返回值可能会与预期值进行比较。
  ●断言的最后一个参数为失败结果的描述字符串,该参数可选,可以不传。一个测试方法可以包括多个断言。 如果其中包含的任何断言报告失败,则Xcode将指示该测试方法失败。使用断言需要的注意是断言的参数类型,可能是BOOL 类型,对象类型,基础数据类型,可能是个表达式等。
  -(void)testUnconditionalFail {
  //1. Unconditional Fail:无条件失败当直接到达特定的代码分支指示失败时使用。
         XCTFail(@"无条件失败....");
  //2.Boolean Tests
      BOOL a = NO;
      XCTAssert(a,@"失败时提示:a == false");
      XCTAssertTrue(a,@"失败时提示:a == false");
      XCTAssertFalse(a,@"失败时提示:a == true");
  //3.基础数据类型
      NSInteger b = 1;
      NSInteger c = 1;
      NSInteger d = 2;
      XCTAssertEqual(b, c, @"失败时提示:b!= c");
      XCTAssertGreaterThan(d, c,@"失败时提示:d < c");
      XCTAssertEqualWithAccuracy(c, d, 1,@"失败时提示:c和d的误差的绝对值大于1");
  //4.对象类型
      NSString *nameA = @"nameA";
      NSString *nameB = @"nameB";
      XCTAssertEqualObjects(nameA, nameB,@"失败时提示:nameA != nameB");
      XCTAssertNil(nameA,@"失败时提示:nameA != nil");
      
  //5. Exception Tests
      NSArray *array = @[];
      XCTAssertThrows(array[0],@"失败时提示:array[0]没有抛出异常");
      XCTAssertNoThrow(array[0],@"失败时提示:array[0]抛出异常");
      XCTAssertThrowsSpecific(array[0], NSException,@"失败时提示:array[0]没有抛出NSException异常");
      XCTAssertThrowsSpecificNamed(array[0], NSException,@"NSRangeException",@"失败时提示:array[0]没有抛出名为NSRangeException的NSException异常");
  }
  ●当Xcode运行测试时,它会独立地调用每个测试方法。因此,每个方法必须准备和清理任何辅助变量。如果此代码适用于类中的所有测试方法,则可以将其添加到setUp和tearDown的实例方法中, 在每个测试方法之前和之后调用。
  //
  -(void)setUp {
      [super setUp];
      // 初始化代码放在这里. 在调用这个类的每个测试方法之前都要调用.
  }
  //
  -(void)tearDown {
      // 销毁代码放在这里. 在调用这个类的每个测试方法之后都要调用.
      [super tearDown];
  }
  您可以选择添加到setUp和tearDown的类方法中,在类中的所有测试方法之前和之后运行。
  //
  +(void)setUp {
      [super setUp];
      // 初始化代码放在这里. 在调用这个类的所有测试方法之前调用.
  }
  //
  +(void)tearDown {
    // 销毁代码放在这里. 在调用这个类的所有测试方法之后调用.
      [super tearDown];
  }
  以下是MZBayTests测试类的基本结构
  //
  -(void)setUp {
      [super setUp];
      // 初始化代码放在这里. 在调用这个类的每个测试方法之前都要调用.
  }
  //
  -(void)tearDown {
      // 销毁代码放在这里. 在调用这个类的每个测试方法之后都要调用.
      [super tearDown];
  }
  //
  -(void)testExample {
      //这是一个功能测试用例的例子。
     //使用XCTAssert和相关函数来验证您的测试是否产生正确的结果。
  }
  //
  -(void)testPerformanceExample {
    //这是一个性能测试用例的例子。
     [self measureBlock:^ {
         //把你想要测量运行的时间的代码放在这里。
    }];
  }
  单元测试中包含普通测试,性能测试,异步测试。
  ●普通测试
  - (void)testModelFunc_randomLessThanTen{
      
      Model * model = [[Model alloc] init];
      
      NSInteger num = [model randomLessThanTen];
      
      XCTAssert(num < 10,@"失败时提示: num should less than 10");
  }
  ●性能测试
  -(void)testAdditionPerformance {
      [self measureBlock:^{
         //把你想要测量运行的时间的代码放在这里。
          
            for (NSInteger index = 0; index < 100000; index ++) {
              NSString *str = [@((index+1) % 100) description];
          }
      }];
  }
  ●异步测试
  - (void)testAsyncFunction{
      //创建一个XCTestExpectation对象。
      //这个测试只有一个,可以等待多个XCTestExpectation对象。
      
      XCTestExpectation * expectation = [self expectationWithDescription:@"Just a demo expectation,should pass"];
      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
          sleep(1);
           NSLog(@"Async test");
          XCTAssert(YES,"should pass");
           //完成相应操作后调用fulfill  这将导致-waitForExpectation
          [expectation fulfill];
      });
      
       //测试将在此暂停,运行runloop,直到超时调用 或所有的expectations都调用了fulfill方法。
      [self waitForExpectationsWithTimeout:0.5 handler:^(NSError *error) {
          //Do something when time out关闭文件等操作
      }];
  }


上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

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

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

沪ICP备05003035号

沪公网安备 31010102002173号