APP重构之路(三) 引入单元测试

栏目: 编程工具 · 发布时间: 7年前

内容简介:本文没有给出任何测试代码,或者是在教你如何编写一份具有良好测试性的代码,而是阐述在重构过程中单元测试的重要性与实现方法,关于代码可测试性相关的内容我会另开一篇文章去具体阐述。(画个饼)在开发过程中我们会遇到这样一些问题:另外我们也许还会遇到一些这样的模块:

本文没有给出任何测试代码,或者是在教你如何编写一份具有良好测试性的代码,而是阐述在重构过程中单元测试的重要性与实现方法,关于代码可测试性相关的内容我会另开一篇文章去具体阐述。(画个饼)

一、为什么要引入单元测试

在开发过程中我们会遇到这样一些问题:

  • 面对需要重构庞大的模块代码时无从下手
  • 修改了一处地方却在另一处地方引发了新的bug
  • 扩展新功能的同时导致旧代码出现bug
  • 在测试人员难以覆盖到的基础功能接口出现了bug
  • 出现了一种难以重现的特殊边界条件触发的bug

另外我们也许还会遇到一些这样的模块:

  • A模块依赖于B模块的结果,但是B模块尚未开发完成
  • 模块状态过于复杂,手工测试需要耗费大量时间
  • 模块业务与时间节点相关,手工测试难以覆盖

这个时候也许能够利用经验和丰富的debug技巧来解决这些问题,但是很多时候我们的处理并不完美,因为我们缺少了一个规范,在编码过程中难以顾及其他模块的影响,这个时候,我们就需要引入 单元测试

二、单元测试的价值

可维护性增强

当在对代码进行修改时,利用单元测试就能够清晰的知道是否破坏了老的业务逻辑,这样大大减少了回归出错的可能性。而当我们从测试那里获得了一个bug时,就可以通过测试用例去还原,当我们这个测试通过后,这个bug也就解决了,而且这个bug fix的测试用例也保证了这个bug以后不会再次出现。

降低重构难度

有了单元测试的保障,我们可以比较大胆的进行重构设计,而单元测试也会成为重构时很好的一个模具。当然在重构时也需要对单元测试进行重构,但是和可靠性相比,这种额外的负担是值得去承受的

减少调试时间

在调试中,我们很多时候都需要花费一些额外的时间来触发需要调试的代码,但是在单元测试中,我们能够针对需要调试的代码构建相关的测试用例,方便的进行反复的测试与模拟,大大减少了调试的时间。

减少低级错误

测试的存在价值就是为我们发现并解决错误,单元测试更是如此,当我们对自己的代码进行单元测试时,就能容易的排除掉一些非常低级的错误,起码我们能够保证在一些正常的情况下代码是可以正确工作的。

描述代码

好的代码就是一份好的文档,单元测试更是如此。一份好的单元测试能够描述在对应的情况下,代码应该有如何的预期表现,那么别人只需要查看测试用例就能清楚的知道代码的功能。

提高代码质量

一份代码如果和其他代码强耦合,它是难以被测试的,所以为了测试,开发人员会被驱使写出低耦合、可扩展的代码。

三、单元测试方案

单元测试中有测试驱动开发(TDD)与行为驱动开发(BDD)两种思路

测试驱动开发(TDD)

  • 根据需求与接口先编写测试用例
  • 根据测试用例编写业务代码
  • 开发效率低
  • 资源耗费大
  • 测试覆盖率高

行为驱动开发(BDD)

  • 通过测试用例描述代码行为
  • 通过自动运行测试用例快速反馈
  • 通过Mock作为相关代码模块的替身
  • 开发效率较高
  • 资源耗费较低
  • 测试覆盖率较TDD要低

基于目前项目的情况与开发流程,我选择了 BDD 作为测试框架,并会选择使用 XCTest + OCMock + OCHamcrest 的方案,以下是三个框架的介绍:

XCTest

XCTest 可以完成的事

  • 基本断言的逻辑判断
  • 异步测试
  • 性能测试

为什么选择 XCTest

  • XCode原生的测试框架,能够更好适应Apple之后的更新
  • XCTest有大量文档支持,上手难度较低
  • XCTest添加进项目后只是作为项目测试框架,并不会影响到打包等一些东西

OCMock

为什么需要 OCMock

mock即为模拟,OCMock可以伪造(模拟)一个对象,给它一些预设的值之类的,并进行对应的验证

比如在我需要测试WiFi直连模块时,我需要一个WiFi才能测试直连功能,这个时候我们就可以利用OCMock,去模拟一个WiFi对象,它可以是模拟成风险WiFi,也可以模拟成免费WiFi,这样我们的直连模块的测试就完全独立于WiFi对象,可以方便的进行测试。

OCMock 可以完成的事

  • 创建一个模拟对象,模拟一个特定对象的行为,排除一些外部类的干扰
  • 构造自己的用例进行验证
  • 对已有方法进行重定义,以自己定义的逻辑进行交互
  • 判断函数是否执行过

为什么选择 OCMock

  • 原生XCTest并不支持Mock功能
  • OCMock是专门为iOS与OS X进行Mock测试的开源项目,拥有超过5000+ app使用,1100万+下载量
  • OCMock使用Apache 2.0协议,能够在需要时候修改代码满足需要并作为开源或商用产品发布/销售
  • OCMock有官方文档,资料齐全

OCHamcrest

OCHamcrest 可以完成的事

  • 更高级的断言
  • 断言可扩展性
  • 支持结构体的断言

为什么选择 OCHamcrest

  • 相对于另一个断言框架 Expecta ,OCHamcrest更为成熟,Expecta可能会导致断言结果错误
  • XCTest 内置断言并不充分,复杂条件下的判断需要编写大量断言代码
  • 利用OCHamcrest的扩展性能够将格式化的自定义log输出到日志文件,提供更多可以定制化而且详细的信息

四、整体测试框架

APP重构之路(三) 引入单元测试

五、应该测试什么 应该怎么测试

测试的原则

  • 快速 :这样才不会介意去运行
  • 独立 :一个测试不应该耦合于另一个测试
  • 可重复 :每次测试的结果应该一致
  • 可验证 :结果应该是成功/失败,而不是一个解释性的日志文档

测试的内容

在写任何测试前,应该明确应该要测试什么,一般的情况下,单元测试应该包括这些内容:

  • 核心功能测试
  • 边界条件
  • 错误处理

测试的思路

针对目前项目情况,我会使用单元测试与人工测试相结合的方式去进行,因为目前我们大部分功能都是与UI牵连,不能完全依靠单元测试去完成所有的测试工作,但是我们可以将逻辑部分进行分离,举网络连接模块为例:

请求流程

APP重构之路(三) 引入单元测试

我们可以对界面相关的部分测试进行拆解,在逻辑部分实现单元测试,而人工测试部分单纯检查整个直连流程和界面部分是否正常。

这样能够避免人工测试时依赖于逻辑的情况,比如在需要测试发起100个请求后模块是否会出现问题时,无需依靠手工去真的连接100次,只需要在单元测试中模拟进行100次连接,并查看结果是否正确就可以。

应该测试的对象

在项目中,我们有大量的类,全部覆盖单元测试是不现实的,我们需要进行挑选。以下是我列举的一些因素。

1.数据相关

比如在本地数据存储模块中,我们需要保存不同的数据,这时候我们可以通过单元测试构造不同的测试数据进行保存,查看是否保存成功,数据部分是单元测试最需要覆盖的部分。

2.逻辑相关

比如在连接模块中,需要对部分请求结果进行过滤,这就是一个逻辑,针对这种逻辑,可以在单元测试中进行测试是否过滤成功,而人工测试则无需关注过滤的逻辑,仅仅需要关注过滤后界面是否正常显示。

3.多状态的模块

比如在连接模块中,连接的状态就有8种,包括了连通性检查、连接中、已连接等,这些状态能够利用单元测试很好的模拟出来,这样就解决了人工测试下难以模拟不同状态转换的问题。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Web Designer's Idea Book

The Web Designer's Idea Book

Patrick Mcneil / How / 2008-10-6 / USD 25.00

The Web Designer's Idea Book includes more than 700 websites arranged thematically, so you can find inspiration for layout, color, style and more. Author Patrick McNeil has cataloged more than 5,000 s......一起来看看 《The Web Designer's Idea Book》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具