单元测试的随想录

上一篇 / 下一篇  2012-05-16 13:56:28 / 个人分类:单元测试

很长时间以来,自己就想写一篇关于单元测试文章。 但是由于自己在某些方面思考得不是很成熟,再加上前一段时间稍微有点忙,所以这个事情就一直这样耽搁下来了。其实,朋友们在开发的时候都知道单元测试是个 好东西,但是真正用于实践,并且在开发中一直保持下去的却是少数。虽然单元测试的框架很多,什么CUnit,CxxUnit等存在很多现成的开源代码框 架,但是大家使用起来还不是很习惯。至于大家为什么会对单元测试很抵触,我想这主要有几个方面的原因:51Testing软件测试网a!y?L:t p lN;?

  (1)单元测试会在无形中增加自己的代码开发量;51Testing软件测试网5?Xq q j)Fw$f

0djc8}a;Rk0  (2)程序员们缺少软件质量的意识,认为保证软件质量是软件测试部门的事情;51Testing软件测试网I&K"S0p\~~1Qo

)HH'J3qXM0  (3)单元测试的效果无法在短期内有所体现,不如功能开发那样立竿见影;

:v&GHH'F'A8V`5B4Z7x051Testing软件测试网D(u4Rj/\

  (4)大家习惯了开发、编译、调试、上机测试、修改这样的传统的开发方式;

;x~7of1j+wdw W051Testing软件测试网;Kw2Q3{vX0_k wN

  (5)项目至上而下缺少质量控制意识,片面追求开发速度、功能数量、入库行数并过度依赖集成测试。51Testing软件测试网wlx&D+s-LK]k

51Testing软件测试网(W'\A4Or9MvKRT

  但是,这里我想说的是每一个程序员都必须对自己的代码负责,不管这段代码是你设计的还是你维护的。单元测试就是一种很好的验证你代码质量的方法。无论是在设计测试用例、理解代码设计、新功能开发、系统理解方面,单元测试都会对你有所帮助。但是,不可否认,单元测试对个人的要求还是很高的,这就需要个人一点点去适应、去改变。

s @ HP/D'QU(X051Testing软件测试网%P{g/h2N[

  a)头文件仿真

|2B+Yj&yE'j0cO B/c0

G f:rR@7J2C0   在单元测试中,为了调用很多的底层函数,通常我们会对某些头文件进行仿真。这个时候,我们引用的函数完全是自己定义和设计的。但是,我们也不能为了现在 的测试修改原来的头文件排布。所以,这个时候就需要对原有的头文件进行仿真。现在,我们假设原来会引用到一个data_type.h文件,中间有我们需要 的函数声明,但是现在不需要了。这时候,我们就可以自己定义一个空的data_type.h文件,添几行代码就可以了。

[,nhq Yc,fEY,W&f;k\0
51Testing软件测试网n]t^1\ UJo

#ifndef _DATA_TYPE_H
0gp"F Dsw0#define _DATA_TYPE_H
51Testing软件测试网%y/D!p+x x\

,Mz$os#_.us!WV_0#endif51Testing软件测试网({:Y s3D}k:T

51Testing软件测试网6D!vq/Y.jO2Y)X*`

  b)数据处理流程和上层接口分开51Testing软件测试网u%qp&d Rs7l,Y

rav?3\0   我们在安排源文件的时候,在安排函数分布的时候要注意一个基本的原则:数据和上层接口分开。在单元测试的时候,我们不太在乎曾经将这个数据的上层包装形 式是什么。只有真正把数据从结构从释放出来,形成一个独立的处理文件,这样我们的测试才更方便、更有针对性。小函数、独立函数、与接口分离的函数,这些都 是我们在代码开发中需要特别注意的。

.F Py&G^6G7N#c?0

w5`)e3U:w f J#H IM0  c)底层驱动打桩处理51Testing软件测试网+l8Z i@3e hv

e6c2@N-qV `;LJ,Tw0  在真实的软件模块中, 我们的代码是不可能独立存在的,因此当前模块的代码常常需要引用别的模块代码。建立符合自己模块的桩函数,一方面可以提高代码的开发效率,另外一方面也方 便我们对自身的代码进行测试。当然,底层驱动打桩函数是多种多样的,某些配置类的函数我们可以象征地输出一行打印就可以了;某些函数我们可以利用测试端的 一个相似函数代替即可;另外本地不存在的一些函数可能还需要我们真正编写代码仿真一把。

E3yYx4h0

?0~)V F\0d)测试用例应该尽量和实际环境一致

4T%V Yh4i9^,B _051Testing软件测试网XbK1t)B&c F

  为了验证代码的正确性,编写测试用例当然是少不了的。但是,编写测试用例并不是说越多越好。重复、低质量的测试用例只会浪费我们的测试资源。那 么,应该怎么做呢?其实真实的运行场景才是我们所关注的。对于我们来说,最重要的就是把那些基础功能、使用最多的功能、最容易犯错的功能设计成测试用例, 剩下的测试用例才是关于覆盖率、性能方面的。51Testing软件测试网qC/UrZ0{a

Y%e cE+o%S e9H0  e)重视代码覆盖率,更加重视功能覆盖率51Testing软件测试网)tu] NW2a{

HB3X0K:\YX2|B,G0  在开发中,很多开发者甚至领导都会把代码测试覆盖率当作单元测试很重要的一个条件。诚然,高的代码覆盖率固然能说明一些问题,但那不是问题的全 部。我们进行单元测试的目的主要是为了验证功能实现和设计是否一致,不是为了测试而测试。当然,在测试中我们可以仿真很多的条件,90%甚至更高的代码覆 盖率都是有可能的。但是,我们需要问一下自己,这些测试和最后的功能测试关系很大吗?如果没有这些测试,会影响最后的功能测试吗?我们假设的这些单元测试 条件在实际运行的时候是真实存在的吗?

}8bEL h0

N'm3{afv.K^R hT S0  f)多线程测试需要日志保存,在程序崩溃的时候生成dump文件51Testing软件测试网'S W Sn7YEgo'@

5zQY1H V0  有些功能的开发,是需要同时运行多个线程的。因此对于某些关键的配置,由于无法保证代码的执行顺序,我们需要对执行过程进行日志记录。如果程序在运行的过程中发生了崩溃,我们也需要及时对关键数据进行记录,保存系统生成的dump文件。51Testing软件测试网V c@ _v7ME |

51Testing软件测试网*w"FR+PZJfZ#v3X9m8dG

  g)测试用例注意生成环境和清除环境51Testing软件测试网.t K*W,n9S)q

1Jt](qEl L0  使用过CUnit的朋友想必对××_init和××_clean非常熟悉。××_init是为了给我们的测试用例构建测试环境,而 ××_clean则是对当前的测试环境进行清理,这样不至于对下面一个测试造成影响。本质上说,CUnit干的就是这么一件事情,在测试用例运行前,自动 调用你的**_init函数,执行结束后自动调用你的**_clean函数。如果你不使用现成的测试框架也没有关系,但是你在测试代码的时候也需要注意环 境的生成和清理问题。51Testing软件测试网D U$Ep8l O

6Ve-eA5x0  h)测试代码也需要保存、重构、模块、分层设计51Testing软件测试网v,x*\a|V7P.l

51Testing软件测试网3k+J @8b!A3Y|6C

  测试代码也不是一层不变的,有的时候为了适应代码的重构需要,我们也需要对测试代码进行重构处理。比如说,有些代码我们是用来测试函数级别的基 本功能的,有些代码我们是测试模块功能的,有的代码我们是测试函数性能的,这些测试代码都需要分开。另外,测试也会按照函数调用顺序不断增加测试的难度和 复杂度的,所以测试代码的分层设计也是十分必要的。51Testing软件测试网|&\I5~NE)\ b

9qz"R v8N)t?p;\P:C0  i)运行带测试用例的实际版本51Testing软件测试网(Ee1W vG:tS

51Testing软件测试网Y(U7u^ZaG

  在版本release的时候,我们是绝不可能在实际版本中存在测试代码的。但是在开发的时候,我们可以自己编译生成带测试代码的版本。所以,我 们需要做的就是保证我们的测试代码不但可以在本地单元测试通过,还需要在实际环境通过。如果在这两方面都能通过的话,那么才能说明我们的测试是成功的,我 们测试是有保障的,否则即使在本地做好了单元测试又有什么意义呢?51Testing软件测试网O$AXTYCSt$UA


TAG:

 

评分:0

我来说两句

Open Toolbar