51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

查看: 485|回复: 0
打印 上一主题 下一主题

[转贴] 在Swift中进行单元测试的详细指南

[复制链接]
  • TA的每日心情
    无聊
    昨天 09:14
  • 签到天数: 938 天

    连续签到: 5 天

    [LV.10]测试总司令

    跳转到指定楼层
    1#
    发表于 2022-7-22 09:35:22 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    当有人第一次听到测试这个词的时候,感觉很可怕。虽然,测试帮助你对你写的代码有信心,而且从长远来看,它们是一种好处。假设你在一个团队中,正在开发一个应用程序。有人错误地交换了一些数据,而这在人工测试中被遗漏了。一个用户抱怨应用程序中的模拟数据。而另一个用户把这个反馈发给你,这样的消息轰炸了你的收件箱。
      想象一下,写一个简单的单元测试来检查这样的手动错误,并在发布前提醒你。很简单,对吗?
      在这篇关于测试和单元测试的介绍性文章中,我们将介绍以下内容:
      为什么要测试?
      作为一个软件开发者,你想确保你所写的代码是按照它应该有的方式工作。尽管这听起来很微不足道,但代码会断裂或发生回归。回归意味着你之前写的代码已经工作了,不再工作了。这就导致了更多的努力去修复它,而不是去做别的事情。为了尽量减少错误,减少人工测试的努力,并让你对代码有信心,你应该写测试。这将有助于你的工作。
      · 减少bug
      错误可能会通过人工测试并进入生产。即使是一个小小的错别字也会产生不利影响。如果有人错误地更新了不应该被触及的代码,写测试可以帮助你在开发的早期发现它们。
      · 重构
      你的目标是将某一段代码隔离开来单独测试。在这个过程中,你可能会重构你的代码,使其更加模块化,有精确的目标。
      · 思考边缘案例
      当你写测试的时候,你要思考可能发生的各种情况,然后写出关于它们的测试。
      · 回归
      在为应用程序添加一个全新的功能后,你不想破坏现有的代码或功能。这就是写测试的巨大帮助。如果你确信新功能不会破坏现有的功能并导致回归,你就会加快开发过程并节省时间。
      要测试什么?
      现在你知道为你的应用程序写测试是很有必要的,以便从长期来看受益于它。但是,到底要测试什么?这是每个人都想知道的问题。写什么测试?
      如果你刚刚开始,最初的几个测试可以是关于测试应用程序的核心业务逻辑。例如,为你在应用程序中定期手动测试的东西编写测试,以确保它在生产中不会损坏。
      什么是单元测试?
      顾名思义,我们测试的是一个特定的单元--可以隔离出来单独测试的一大块代码。从网络调用,测试缓存的逻辑到你模型中的计算变量。我们有一个预定义的输入,然后在一个测试方法中检查特定的代码块的预期值和结果。
      苹果公司为我们提供了一个名为XCTest的本地框架用于单元测试。还有其他的开源框架,如Quick和Nimble,但在这篇文章中我们将重点介绍XCTest。
      了解XCTest和XCTestCase
      XCTest是苹果公司的一个框架,帮助我们创建和运行单元、性能和UI测试。在这篇介绍性文章中,我们将只专注于创建单元测试。该框架为我们提供了两个主要的类--
      ·XCTest - 作为创建、管理和执行测试的基类。
      ·XCTestCase - 是定义测试案例、测试方法和性能测试的主要类,继承自XCTest 。
      每个测试类都有一个生命周期,我们可以在运行前设置初始状态,在测试完成后进行清理。
      XCTest 和XCTestCase 提供各种类型和实例方法,其中setUp() 和tearDown() 是两个主要的。
      setUp() 方法是用来在测试运行前定制初始状态的。例如,在测试方法中初始化一个数据结构,并为每个测试案例重置其初始状态。
      tearDown() 方法是用来在测试运行后进行清理。例如,为了删除任何引用,我们将初始化数据结构的实例设置为nil。
      有两种类型的方法提供给我们,即
      · 类方法,用于设置初始状态和对所有测试方法进行最终清理。在这里,我们分别覆盖了setUp() 和tearDown() 类方法。
      · 实例方法,用于设置初始状态和对每个测试方法进行清理。同样地,我们分别覆盖setUp() 和tearDown() 实例方法。
      现在我们已经完成了基本原理,是时候在Xcode中实际实现它了!所以,现在是时候继续学习更详细的Xcode单元测试教程了。
      在Xcode中添加一个单元测试
      每当你创建一个新项目时,你可以选择勾选包含测试。这些包括单元测试和UI测试。

    如果你已经有了一个项目,你也可以添加一个单元测试包到其中。转到文件>新建>目标。

    选择iOS Unit Testing Bundle,然后点击Next。

    当你为你的项目创建一个新的单元测试目标时,它包括一个模板。它是测试案例的生命周期。让我们来看看文件的内容 :
      setUp() 实例方法每次在测试方法运行前都会运行。你覆盖它来添加你自己的实现。如果你想在一个测试类中运行一次初始代码,请覆盖setUp() 类方法来代替。
      与之前的setUp() 方法类似,要在每次测试方法后清理状态,请覆盖tearDown() 实例方法。对于在测试类中清理一次,请覆盖tearDown() 类方法来代替。
      测试实例
      在这篇文章中,我们将测试TallestTowers,这是一个显示世界各地最高的塔的应用程序,以及关于它们的信息。你可以在这里下载该项目。
      在TallestTowers中,我们显示一个最高的塔的列表。而最重要的测试代码是检查该列表是否为空。
      每当写一个测试时,我们在方法前加上 "test "这个词,这样Xcode就会理解它是一个可测试的函数。我们创建一个继承自XCTestCase 的类TowerStaticTests ,并在TowerStaticTests 中添加以下方法------:
    1. class TowerStaticTests: XCTestCase {
    2.     func testTallestTowersShouldNotBeEmpty() {
    3.       XCTAssert(Tower.tallestTowers.count > 0)
    4.     }
    5.   }
    复制代码
     我们从Tower 模型中获得静态变量tallestTowers ,并断言计数是否大于零。如果是的话,测试就会以绿色检查通过。
      另一组要写的测试是针对Tower 的数据模型。我们计算位置,并将城市和国家名称与正确格式化的高度连接起来。我们将写一些单元测试,以确保这些计算的每个属性总是返回预期的输出。
      首先,我们创建另一个继承自XCTestCase 的类,名为TowerInstanceTests 。我们声明一个类型为Tower的主题变量。在setUp() 方法中,用模拟数据初始化该变量。最后,我们重写tearDown() 方法,将主体设置为nil:
    1.  class TowerInstanceTests: XCTestCase {
    2.     var subject: Tower!
    3.     
    4.     override func setUp() {
    5.       subject = Tower(name: "Empire State Building", city: "New York City", country: "USA", height: 381, yearBuilt: 1931, latitude: 40.748457, longitude: -73.985525)
    6.     }
    7.     
    8.     override func tearDown() {
    9.       subject = nil
    10.     }
    11.   }
    复制代码
    通过测试的长名字,我们特别提到了测试案例的内容。例如,测试地点应该由纬度和经度属性创建。所以,我们用骆驼的方式命名测试用例:
    1. func testLocationShouldBeCreatedFromLatitudeAndLongitudeProperties() {
    2.     XCTAssertEqual(subject.location.latitude, 40.748457, accuracy: 0.00001)
    3.     XCTAssertEqual(subject.location.longitude, -73.985525, accuracy: 0.00001)
    4.   }
    5.   func testCityAndCountryShouldConcatenateCityAndCountry() {
    6.     XCTAssertEqual(subject.cityAndCountry, "New York City, USA")
    7.   }
    8.   func testFormattedHeightIncludesUnits() {
    9.     XCTAssertEqual(subject.formattedHeight, "381m")
    10.   }
    复制代码
    通过写一些测试,我们感受到了如何写一个测试,以及测试什么!
      命名的提示
      每当写一个测试时,我们在方法前加上 "test "这个词,这样Xcode就会理解它是一个可测试的函数。
      写长的方法名称。要具体。如果一个测试在众多的测试中失败了,那么名字的一瞥应该足以让你知道什么失败了。例如,如果testTallestTowersShouldNotBeEmpty() ,我们知道列表是空的。
      调试一个单元测试
      我们使用Xcode提供的标准工具调试,也是为了调试单元测试。在检查了任何逻辑或假设错误后,如果测试仍然失败或没有输出预期结果,我们可以使用测试失败断点。
      转到断点导航器,选择添加按钮(+):

    从下拉菜单中,选择添加测试失败断点。这在开始测试运行前设置一个特定的断点:

    每当你运行一个测试,并且测试用例发布一个失败的断言时,该断点就会被触发。这有助于了解测试失败的地方,测试的执行也会停止:

    启用代码覆盖
      Xcode有内置的代码覆盖,以测试你的测试是否覆盖了所有的代码。要启用这个选项,请进入TallestTowers并点击Edit Scheme....从侧边栏选择测试选项,从分段控制中选择选项。勾选 "收集所有目标的覆盖率":

    再次运行测试(Command + U)。从项目导航器中选择报告导航器,并点击最近的一个测试。选择覆盖率选项。你会发现所有被测试的文件,其覆盖率的百分比和可执行行:

    由于我们彻底测试了Tower模型,我们可以看到95.5%的代码覆盖率。
      要在编辑器中看到代码覆盖率,请选择编辑器选项并勾选代码覆盖率:

    尽管拥有良好的代码覆盖率是很好的,但以100%为目标并不理想。
      在CI中用Fastlane和Semaphore实现单元测试自动化
      为了使测试过程自动化,我们将使用Fastlane,目的是简化部署。有多种方法可以安装Fastlane,我们将使用Homebrew。打开终端,运行命令:
    1. brew install fastlane
    复制代码
    改变目录到项目并运行:
    1.   fastlane init
    复制代码
    现在,打开位于项目文件夹中的Fastfile ,并在其中添加以下几行 :
    1.  lane :tests do
    2.     run_tests(scheme: "TallestTowers")
    3.   end
    复制代码
    最后,为了运行测试,在终端执行以下命令:
    1.   fastlane tests
    复制代码
    为了使持续集成的过程自动化,你可以使用Semaphore服务。
      结论
      当临近截止日期时,很难专注于编写测试,但慢慢地你会发现,从长远来看,这是有好处的。编写测试可以提高代码质量,减少错误和回归,随着时间的推移加快开发进程。带着信心去写一些测试吧!
      另外,花些时间为你的应用程序配置CI/CD,以专注于编写代码和提供良好的用户体验,而不是每次都手动交付应用程序。








    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?(注-册)加入51Testing

    x
    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-4-27 22:54 , Processed in 0.066250 second(s), 24 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表