不管是开发还是重构, 这个过程都会涉及到重构的概念 , 看看这个概念要怎么进行处理? 如何简历更好的单元测试;
使用书籍: 《单元测试的艺术》
我们通过系统的公共API和行为就可以光差到一个可见的最终结果, 无需查看系统的内部装填。
一个最终结果可以是一下任何一种形式:
1》 被掉员工公公公方法返回一个值(一个放回不为空的函数)
2》在方法调用的前后, 系统的装填或系统有可见的变化,,或者一个状态机系统的舒心发生变化
3》调用了一个不受测试控制的第三方系统, 这个第三方系统不返回任何值。 或者返回的值是被忽略的。 (eg: 调用一个第三方日志系统, 这个系统不是你编写的, 而且你也没有源代码。)
单元测试 、 工作单元、 优秀单元测试【保证代码治质量很重要】
QR : 什么是单元测试?? 什么不是单元测试?
集成测试:相对比较慢,
集成测试的另一个问题:一次测试的东西踏跺
与自动化单元测试相比, 非自动化集成测试的缺点:
1) 一段时间之后,该测试不同通过。 定义:回归是以前运行良好但是现在不通过的一个或多个工作单元
2)当我们改动代码的 时候,不会破坏别人的代码。 不直达搜系统修改后的状态是否稳定。
1)能在几分钟内跑完我写过的所有单元测试吗?
2)我一键运行我写过的额所有单元测试吗?
3)在几分钟内写出一个基本的测试吗?
QR: 什么是优秀的单元测试
QR: 如何编写单元测试? 在开发过程中应该何时编写单元测试。
1.6 测试驱动开发
编写结构化、可维护 和 可靠的测试。
很多人觉得为软件编写单元测试的最佳时机是软件编码完成以后, 但是越来越多的人选择在产品代码编写之前写单元测试。 —— 测试优先或测试驱动开发 (test driveen development , TDD )
我们必须意识到, TDD并不能够保证项目一定成功、或者测试都健壮、可维护。
TDD技术:
1)编写一个会失败的测试, 以证明产品中代码或者功能的缺失
2) 编写符合测试预期的产品代码, 使测试通过。 —— 产品代码尽量简单
3)重构代码 —— 写下一个单元测试或者重构代码
重构可以编写多个测试之后进行,也可以在每个测试后都进行。 重构确保 —— 代码容易读、更好维护、通过编写的所有测试。
TDD一个最大的有点:
(1)如果一个测试失败了,没有经过修改再次运行又成功了,你其实是在测试这个测试本身。
(2) 如果你预期一个测试失败了,但它却成功了,那么测试本身可能有缺陷, 或测试的对象不对。
(3)如果一个测试之前失败了,你现在预期它成功,它却依然失败,那测试可能有缺陷, 或测试预期的结构不正确。
测试两个方面: 该失败的时候失败,该成功的时候成功
1.7 成功进行TDD的三种核心技能
知道如何编写优秀的测试、在编码前编写测试、良好的测试设计
1) 仅仅做到先编写测试,并不能够保证测试是可维护、可读以及可靠的。
2)仅仅做到编写的测试可读、可维护、并不能保证你获得先编写测试的各种好处。
3)仅仅做到先编写测试,并且测试可读,可维护,并不能够保证你得到一个设计完善的系统。
第一个单元测试
QR:首先考虑一个问题: 我们需要考虑什么是单元测试框架, 用它能够做什么以前不能也不会做的事?
AS: 手工进行测试和回归测试,很容易出错、浪费时间。单元测试框架可以帮助开发人员使用一套已知的API更快地编写测试, 自动执行这些测试,轻松查看结果。
2.1.1 单元测试框架提供什么?
- 不是结构化的。 每当要测试一个新功能要重新写代码。 一个测试可能看着像控制台程序,另一个测试使用UI窗体,另一个又是web表单。 没有多余的时间花费在测试上, 这些测试都没有达到“容易实现”这个要求。 —— 看看,这个和UI相关的并不是那么容易实现?
- 不可重复。 无法运行以前编写的测试,这个就是不可重复。
- 不能覆盖代码的所有重要部分。 测试没有测试到所有重要的代码。 —— 更高的重要代码的覆盖率。
—— 编写、运行和查看单元测试及其结果的框架。
单元测试 : 帮助开发人员进行单元测试的代码库和模块。 —— 作为自动编译过程的一个步骤进行测试。
像我们的iOS, 就应该先了解XCTest里面的每一个方法,具体是实现了什么东西? 然后再进行处理这个内容。
Assert方法, 这个方法有很多其他的类型,不同的判断,也就是我们对结果的判断。
测试代码: 校验测试代码和业务代码,修复代码让其通过测试。
2.4.3 添加正检验 —— 也就是验证,我现在的情况是正确的。 当然,还有其他的情况排除, 这些情况排除是我们在写测试用例的时候,就应该处理掉的。
测试代码格式
1)尽量把断言和操作对象代码分开。 让测试代码更加的易读。
2.5 > 使用参数重构测试
有关测试的框架步骤以及过程:
setup & teardown 测试框架基本上都有的;
保证创建和销毁的对象的状态,这个过程可以有根据的判断。
2.6.1 > 执行的流程
setup ——> 执行代码 ——> teardown
ios 中有两个测试: 一个是基本单元测试;一个是集成测试;
2.6.2 > 检验预期的异常
一个常见的测试场景是:保证当异常应该抛出时, 被测试的方法能够抛出正确的异常。
所以,我们不仅仅使用了断言,同事我们应该也使用了异常的判断。
异常的测试: 我们可以使用try/catch 要判断出来在哪个位置
忽略测试, 看看我们iOS中有没有忽略的测试
ios 中没有忽略测试这个概念; (情况很少见,所以,iOS基本上就没有这个东西了)
断言方法的使用
设置测试类别, 看看那iOS 中有没有可以测试的类别;
2.7 测试系统状态的改变而非返回值
前面是对工作单元最简单的结果: 返回值进行测试
现在: 系统状态改变 —— 检验被测试系统在执行某个动作前后其行为发生变化。
使用存根破除依赖
简单例子里面: 测试只需啊哟检查对象的返回值,或者一个简单系统里的被测试单元状态
要测试的对象依赖另一个你无法控制(或者还未实现)的对象。 这个对象可能是web服务、系统时间、线程调度或者很多其他东西。 重要的问题是:你的测试代码不能控制这个依赖的对象放你的代码返回什么值, 不不能够控制它的行为。 —— 就可以使用
存根
:::也就是里面依赖了不可预知的变化。
定义:一个外部依赖项(external dependency) 是系统中的一个对象, 被测试代码与这个对象发生交互,但你不能控制这个对象。(常见的外部依赖项包括:文件系统、线程、内存以及时间等)
使用存根来回避外部依赖项的问题。
定义:一个存根(stub)是对系统中存在的一个依赖项(或者协作者)的可控制的替代物。 通过使用存根,你在测试代码时无需直接处理这个依赖项。
第4章中将 对 存根(stub) 、模拟对象(mock)以及伪对象(fake)的定义并讨论它们之间的关系。
存根和模拟对象的区别: 模拟对象和存根很类似,但是你会对模拟对象进行断言,而不会对存根进行断言。
破除依赖的确定模式:
3.4 重构代码设计以提高可测试性
重构: refactoring
接缝: seam
3.4.1 抽取接口使底层实现可替换
3.4.3 在构造函数层注入一个伪对象
给被测试类添加一个新的构造函数。传入一个之前抽取出来的接口类型的对象,然后在被测试类中添加一个这个接口类型的局部字段,把传入的对象赋给这个布局字段,供被测试方法或其他方法使用。
伪对象放在和测试代码同一个位置里面,会更加好维护管理;
2. 什么时候应该使用构造函数注入
3.4。4 》 用伪对象模拟异常
3.4.5 用属性的get或者set注入伪对象
3.4.6 在方法调用前注入伪对象
___ [这哪是略过]
重构技术变种:
【其他暂时略过】
第5章 隔离(模拟)框架
5.1 为什么要使用隔离框架
5.2 动态生成伪对象
5.3 模拟值
5.4 测试时间相关的活动
5.5 现有的.net 隔离框架
5.6 隔离框架的优缺点
5.7 小结
6、深入了解隔离框架
6.1 受限框架及不受限框架
6.2 优先的隔离框架的价值
6.3 支持适应未来和可用性的功能
第三部分: 测试代码
测试层次和组织
7.1 运行自动化测试的自动化构建
7.2 基于速度和类型布局测试
7.3 确保测试是源代码管理的一部分
7.4 将测试类映射到被测试代码
7.5 注入横切关注点
7.6 为应用程序构建测试API
7.7 小结:
8.优秀单元测试的支柱:
8.1 编写可靠的测试
8.2 编写可维护的测试
8.3 编写可读的测试
小结:
第4部分:设计和流程
第9章节: 在阻止中引入单元测试
第10章节:遗留代码
第11章节:设计与可测试性