Testing 的第一个切入点:单元测试。
本篇文章将针对单元测试进行简介,主要内容包含了5W:
而How 的部分,属于实现部分,将于下一篇文章介绍工具与简单的范例。
最后会提到测试用例所代表的意义与其重要性。
单元测试,是开发人员最该写的测试程序,却也是最容易被忽略的测试。
大家常碰到的测试相关问题是:
看完这几篇单元测试的相关文章后,希望大家可以获得一些想法,解决这些问题。
先举几个在开发上常见的问题:
这些问题,可以有哪些Unit Test 相关的方式来解决:
总而言之,没有被测试涵盖到的程序,即使它可能是对的,也没人敢拍胸脯保证。而有了测试用例来辅助说明与保护,至少可以拍胸脯保证,在这样的测试用例下,这个对象的设定,肯定如同预期般执行。
而单元测试可以提供回归测试的保护,在每一次异动完程式,可以单键执行就知道是否破坏了原本对对象行为的预期。
单元测试可以透过一些辅助设计,来达到与外部环境、服务、相依隔绝,而仅测试该物件本身的逻辑,以及与外部的互动是否符合预期。
造成问题的测试案例,往往是最珍贵的,因为最具代表性,也最具价值。因为它提供了我们修正bug的方向以及指标。而针对发生问题的测试案例,来执行单元测试,马上就可以知道是否是该对象的内部问题。
最后,单元测试由于具备与外界服务、相依隔绝的特性,所以可以帮助撰写实际的对象时,具有可测试性、低耦合性,彼此之间只相依于抽象或接口。进而通过IoC 的设计,让我们可以做到关注点分离,让开发各个对象的developer,可以透过接口来沟通,不相依于彼此实现,就能平行开发。
Unit Test 的定义与基本准则,如下图所示:
Unit Test的特性,一个字:FIRST。如下图所示:
即:优良的单元测试具有以下的特点:简称为 A-TRip。
- 自动性(Automatic)
- 完备性(Thorough)
- 可重复性(Repeatable)
- 独立性(Independent)
- 专业性(Professional)
单元测试的覆盖范围,以定义来说,单元测试是最小的测试单位,在面向对象中,就是测试一个方法。而方法一定会在某个对象上(即使是静态方法,也是在类型对象上)。
所以,单元测试通常就只关注在测试的目标对象上,而不管目标对象以外的东西,例如:目标对象所相依的实体对象、相依服务、相依资源、相依环境等等...
单元测试,简单的说,就是用来模拟外部如何使用这个目标对象,或是如何与这个目标对象互动。所以我们所撰写的单元测试程序,就是模拟与目标对象互动的程序。测试案例,就是该互动下的情境。接着验证物件的行为是否符合我们预期。
因此,单元测试程式,既然是模拟外部如何使用目标物件,所以也只会针对目标对象对外开放的方法。
而基本上,单元测试透过哪些方式去验证对象的行为符合预期呢?简单来说,有三种:
单元测试该由谁来撰写,就如同前言所说,最应该撰写的是developer,而非QA/QE。
就如Where段落所说,单元测试简单的说,是我们在设计对象的时候,预期外部该如何使用这个对象,进而衍生出对象该提供什么样的功能、具备什么样的行为。正因为对象的设计人、使用人,都是developer,所以单元测试的程式,当然由developer来设计,最为妥当。尤其由用的人来写,最为精准。
归纳几个基本要点:
撰写单元测试的时机点,简单分成三个:
想清楚,外部的需求是什么,才能设计出符合需求的对象。
当需求异动时,自然需要针对新的需求,来设计新的测试程序,因为这样才能驱使目标物件行为的改变。
当出现非预期的执行结果时,通常代表目标物件有着非预期的行为发生,有可能是当初测试案例不足,所以要增加我们的「预期」。
也有可能是当初预期的结果就错了,那其实就可以当作是第二点,需求的异动。(当然对使用端来说,还是属于bug,但对对象设计来说,测试案例方向就错了)
大家买过3C产品或电器吧,基本上拿到一个东西,我们都会先看使用说明书。
大家肯定也写过一堆「系统分析书」、「代码规格书」、「SA/SD 文件」等等...但这些文件,跟最后线上的代码,究竟有多少是相同的呢?文件越详细,代表后面修改的effort 越大。
因为软件设计,本来就是个需求频繁变动的过程,往往大家只想「冻结需求」,却很常因为「冻结需求」搞到作出来的系统难用,因为不符合使用者需求。
我们期望的是,每一次的需求异动,都是软件进化的动力,每一次的异动,都是品质的累积,以及更符合使用者的需求。
而文件呢?只有一开始分析、设计爽的,因为代码写下去,跟文件搭不搭的起来,只有三个人知道,一个已经离职了,一个是我,另一个我不能说。
鲜少会有文件跟着代码一直进行更新的。
但文件却又是辅助了解与说明很重要的东西,那怎么办?很简单,会一直活着的,就只有代码。要验证代码是否符合我们预期,最简单的方式,就是用代码验证它的行为,一翻两瞪眼,现在的物件究竟满足了那些功能,哪些情境下可以跑出预期结果,测试案例一目了然。
所以,测试案例的意义与价值是什么?
代码即文件,高兴什么时候产生文件,就什么时候产生,保证即时、可运作、童叟无欺。测试案例上面有的,肯定work,而测试案例上面没有的,不一定会错,但不打包票。
一句话总结:「Working software is based on working test cases」。
Working software 是TDD 的整个骨架,也是user 最需要的东西。
备注:这个系列是我毕业后时隔一年重新开始进入开发行业后对大拿们的博文摘要整理进行学习对自我的各个欠缺的方面进行充电记录博客的过程,非原创,特此感谢91 等前辈
新闻热点
疑难解答