iOS开发—单元测试和UI测试教程(上)

发表于:2022-5-18 09:33

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

 作者:小小小_小朋友    来源:稀土掘金

  弄清楚要测试什么
  在编写任何测试之前,了解基础知识很重要。你需要测试什么?
  如果您的目标是扩展现有应用程序,您应该首先为您计划更改的任何组件编写测试。
  通常,测试应涵盖:
  ·核心功能:模型类和方法及其与控制器的交互
  · 最常见的 UI 工作流程
  · 边界条件
  · Bug修复
  了解测试的最佳实践
  首字母缩略词FIRST描述了一组简洁的有效单元测试标准。这些标准是:
  · 快速:测试应该快速运行。
  · 独立/隔离:测试不应该相互共享状态。
  · 可重复:每次运行测试时都应该获得相同的结果。外部数据提供者或并发问题可能会导致间歇性故障。
  · 自我验证:测试应该是完全自动化的。输出应该是“通过”或“失败”,而不是依赖于程序员对日志文件的解释。
  · 及时:理想情况下,您应该在编写测试的生产代码之前编写测试。这被称为测试驱动开发。
  遵循 FIRST 原则将使您的测试保持清晰和有用,而不是成为应用程序的障碍。
  Xcode 中的单元测试
  测试导航器提供了使用测试的最简单方法。您将使用它来创建测试目标并针对您的应用运行测试。
  创建单元测试目标
  打开BullsEye项目并按Command-6打开测试导航器。
  单击左下角的*+*?,然后从菜单中选择New Unit Test Target... :
  接受默认名称BullsEyeTests并输入com.raywenderlich作为组织标识符。当测试包出现在测试导航器中时,通过单击显示三角形将其展开,然后单击BullsEyeTests以在编辑器中打开它。
  默认模板导入测试框架XCTest,并定义、with和示例测试方法的BullsEyeTests子类。
  XCTestCase``setUpWithError()``tearDownWithError()

  您可以通过三种方式运行测试:
  1. 产品 ->测试或Command-U。这两个都运行所有测试类。
  2. 单击测试导航器中的箭头按钮。
  3. 单击装订线中的菱形按钮。
  您还可以通过单击测试导航器或装订线中的菱形来运行单个测试方法。
  尝试不同的方法来运行测试,以了解它需要多长时间以及它的外观。样本测试还没有做任何事情,所以它们运行得非常快!
  当所有测试都成功后,菱形将变为绿色并显示复选标记。单击末尾的灰色菱形testPerformanceExample()打开性能结果:
  本教程不需要testPerformanceExample()或不需要testExample(),因此请删除它们。
  使用 XCTAssert 测试模型
  首先,您将使用XCTAssert函数来测试 BullsEye 模型的核心功能:是否BullsEyeGame正确计算了一轮得分?
  在BullsEyeTests.swift中,在下面添加这一行import XCTest:
  @testable 导入BullsEye

  这使单元测试可以访问 BullsEye 中的内部类型和函数。
  在 的顶部BullsEyeTests,添加此属性:
  var sut: BullsEyeGame! 

  这将创建一个占位符BullsEyeGame,即被测系统(SUT),或此测试用例类与测试相关的对象。
  接下来,将 的内容替换为setUpWithError():
  尝试 超级.setUpWithError()
  sut =  BullsEyeGame ()

  这会BullsEyeGame在类级别创建,因此该测试类中的所有测试都可以访问 SUT 对象的属性和方法。
  在你忘记之前,释放你的 SUT 对象tearDownWithError()。将其内容替换为:
  sut =  nil
  尝试 超级.tearDownWithError()

  注意:最好在其中创建 SUTsetUpWithError()并将其释放,tearDownWithError()以确保每次测试都以干净的状态开始。如需更多讨论,请查看Jon Reid关于该主题的帖子。
  编写你的第一个测试
  现在您已准备好编写您的第一个测试!
  将以下代码添加到末尾BullsEyeTests以测试您是否计算了猜测的预期分数:
  func  testScoreIsComputedWhenGuessIsHigherThanTarget () {
     // 给
    定letguess = sut.targetValue +  5
    // 什么时候
    sut.check(猜测:猜测)
    // 然后
    XCTAssertEqual (sut.scoreRound, 95 , "从猜测计算的分数是错误的" )
  }

  测试方法的名称总是以test开头,后跟对其测试内容的描述。
  将测试格式化为given、when和then部分是一种很好的做法:
  1. Given:在这里,您可以设置所需的任何值。在此示例中,您创建了一个guess值,以便您可以指定它与targetValue.
  2. 何时:在本节中,您将执行正在测试的代码:调用check(guess:)。
  3. 然后: 这是您将通过在测试**失败时打印的消息断言您期望的结果的部分。在这种情况下,sut.scoreRound应该等于 95,因为它是 100 - 5。
  通过单击装订线或测试导航器中的菱形图标运行测试。这将构建并运行应用程序,菱形图标将变为绿色复选标记!您还会在 Xcode 上看到一个短暂的弹出窗口,它也表示成功,如下所示:
  注意:要查看**XCTestAssertions的完整列表,请转到Apple 的 Assertions Listed by Category。
  调试测试
  有一个故意内置的错误BullsEyeGame,您现在将练习查找它。要查看实际中的错误,您将创建一个从给定部分中减去 5 的测试,并使其他**所有内容保持不变。targetValue
  添加以下测试:
  func  testScoreIsComputedWhenGuessIsLowerThanTarget () {
     // 给
    定letguess = sut.targetValue -  5
    // 什么时候
    sut.check(猜测:猜测)
    // 然后
    XCTAssertEqual (sut.scoreRound, 95 , "从猜测计算的分数是错误的" )
  }

  guess和之间的差targetValue仍然是 5,所以分数应该仍然是 95。
  在 Breakpoint 导航器中,添加一个Test Failure Breakpoint。当测试方法发布失败断言时,这会停止测试运行。

  运行你的测试,它应该在XCTAssertEqual测试失败的那一行停止。
  检查sut并guess在调试控制台中:
  guess是targetValue ? 5但是scoreRound是 105,而不是 95!
  要进一步调查,请使用正常的调试过程:在when语句中设置断点,并在BullsEyeGame.swift的 inside中设置断点check(guess:),它会在其中创建difference.?然后,再次运行测试,并跳过let difference语句以检查difference应用程序中的值:
  问题是difference负数,所以分数是 100 - (-5)。要解决此问题,您应该使用的绝对值。difference在check(guess:)中,取消注释正确的行并删除不正确的行。
  删除两个断点并再次运行测试以确认它现在成功。
  使用 XCTestExpectation 测试异步操作
  现在您已经了解了如何测试模型和调试测试失败,是时候继续测试异步代码了。
  BullsEyeGame用于URLSession获取一个随机数作为下一场比赛的目标。URLSession方法是异步的:它们立即返回,但直到稍后才完成运行。要测试异步方法,请使用XCTestExpectation让您的测试等待异步操作完成。
  异步测试通常很慢,因此您应该将它们与更快的单元测试分开。
  创建一个名为BullsEyeSlowTests的新单元测试目标。打开全新的测试类并在现有语句下方BullsEyeSlowTests导入BullsEye应用程序模块:import
  @testable 导入BullsEye

  该类中的所有测试都使用默认URLSession发送请求,因此sut在中声明、创建setUpWithError()和释放tearDownWithError()。为此,请将以下内容替换为BullsEyeSlowTests:
  var sut: URLSession!
  覆盖 func  setUpWithError () throws {
     try  super .setUpWithError()
    sut =  URLSession(配置:.default)
  }
  覆盖 func  tearDownWithError ()抛出{
    sut =  nil
    尝试 超级.tearDownWithError()
  }

  接下来,添加这个异步测试:
  // 异步测试:成功快,失败慢
  func  testValidApiCallGetsHTTPStatusCode200 () throws {
     // 给定
    let urlString =  
      "http://www.randomnumberapi.com/api/v1.0/random?min=0&max=100&count=1" 
    let url =  URL(字符串:urlString)!
    // 1 
    let promise = expect(description: "状态码: 200" )
    // 当
    let dataTask = sut.dataTask(with: url) { _ , response, error in 
      // then 
      if  let error = error {
         XCTFail ( "Error: \(error.localizedDescription) " )
         return 
      } else  if  let statusCode =(响应为? HTTPURLResponse)?.statusCode {
         if statusCode ==  200 {
           // 2
          promise.fulfill()
        } else {
           XCTFail ( "状态码: \(statusCode) " )
        }
      }
    }
    数据任务.resume()
    // 3
    等待(for: [promise], timeout: 5 )
  }

  此测试检查发送有效请求是否返回 200 状态代码。大多数代码与您在应用程序中编写的代码相同,只是添加了以下几行:
  1. 期望(描述:):返回XCTestExpectation,存储在promise.?description描述您期望发生的事情。
  2. promise.fulfill():在异步方法的完成处理程序的成功条件闭包中调用它以标记已满足期望。
  3. wait(for:timeout:):保持测试运行,直到满足所有期望或timeout间隔结束,以先发生者为准。
  运行测试。如果您已连接到 Internet,则在模拟器中加载应用程序后,测试应该需要大约一秒钟才能成功。

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

关注51Testing

联系我们

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

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

沪ICP备05003035号

沪公网安备 31010102002173号