Chinaunix首页 | 论坛 | 博客
  • 博客访问: 512593
  • 博文数量: 78
  • 博客积分: 995
  • 博客等级: 准尉
  • 技术积分: 1462
  • 用 户 组: 普通用户
  • 注册时间: 2011-11-15 20:22
个人简介

技术中沉思的时候最快乐,问题得到完美解决的时候最有成就感!

文章分类

全部博文(78)

文章存档

2013年(39)

2012年(37)

2011年(2)

分类: LINUX

2012-08-27 12:05:23

曾惊奇的发现,某复杂的包括n个server节点的系统没有任何单元测试代码,没有svr client,压力

测试更谈不上了,所有的测试竟然完全依赖于windows客户端;开发流程倒是简单到粗暴--每个人负责一到两
个svr,每个先写自己的代码,写完之后,启动,然后等他人联调,往往等一个人是不够的,是要等所有的人
都写好后,特别是客户端的开发;好,代码写完了,联调,客户端的人在界面上进行某操作,客户端发出一个
包,然后传递到接口svr,接口svr把包分发到后面的svr,后面的svr再转给dbp之类的;时间一般是这样分配
的,代码开发30%,联调30%,提交测试30%,剩下的10%用来扯...

其实我以前的项目就这样做的,我估计非常多非常多的项目都用的这一方法;tecent 也差不多,没
有单元测试,我问过为什么,回答说浪费时间,貌似很有道理...Tencent有一套完整的框架代码,所以client
肯定是有的,还好,所以每个svr都可以做接口测试,但这个client貌似应该是c或者c++构筑的,估计想要改
或者想以此为基础做压力测试测试还是比较恶心的;

这样的项目如果逻辑简单,业务节点种类较少,也不会有什么大问题,最多就是联调时间多点而已,
不过因为少了单元测试+接口测试的时间,最后的开发效率应该差不多了多少;
但如果项目繁杂,业务节点多种,随着项目代码的迭代和更改,最后的系统肯定是摇摇欲坠的;
表现几点:
1,线上系统bug,core不断,数据出问题或丢失不过是家常便饭;
2,各个svr节点都成了黑盒子,出了问题,除了查log之外基本束手无策,或者只能让测试拿客户端
不断重试,希望能重现,然后立即再查日志;
3,监控成了大问题,运维一般是希望能提供接口层的监控,但因为没有完整灵活可变的client,想
要监控svr基本不可能;
4,系统沉重不堪,仿佛在齐腰深的水中步行,两个字--艰难;改一个小小的地方,都要走冗长的
测试流程,让测试人员进行一遍又一遍的黑盒测试;因为系统沉重,迭代速度变得非常缓慢,发版速度和客
户端一样,需要十分的谨慎;

解决办法:单元测试+接口测试+压力测试

单元测试
其实过去我和绝大部分的开发一样,讨厌或者不愿意做单元测试,虽然看过一些书,比如敏捷开发
之类,测试驱动开发之类;但实践起来,往往发现根本不可能,或者不顺手,或者完全和过去的开发习惯不
一致,最后的结果往往是放弃;

我的感受,或者说我的理解,也是我的做法:
1,完全说测试驱动开发,这个比较狗屎,基本不可能,一些复杂的多变的业务代码光写单元测试
代码都是件难事,特别是一些多次异步的操作(和后台几个svr交互)完全没办法写单元测试代码,因为这
些操作依赖于网络,依赖于异步...
2,简单的几行代码,完全没必要写单元测试,确实浪费时间,写单元测试代码是有成本的,特别
是测试用列的选择,常常需要消耗脑细胞的;
3,上面说了:业务代码不要写单元测试,简单代码不写,那哪里写单元测试?我的理解以及我的
个人经验:容易出错的地方,复杂的地方,特别是一些底层算法和核心数据结构,极其需要单元测试的;往
往这些地方是svr中的核心代码,也是最易滋生bug的地方;比如:我觉得没几个人能一次把list这个数据
结构写的完全正确;另外历史上的快排算法,据说算法出了n年后,才有一个正确的真正实现;我们在开发
中一定要避免复杂不必要的算法;质量是第一位的,当拿不定的时候就穷举,千万不要片面的追求牛逼算法
跑题了,但有时确实是无法避免的,既然无法避免,那就要用什么方法来保证质量,答案是:单元测试;

为什么?因为:
单元测试把这些容易出错复杂的地方从繁杂冗长的代码中单独剥离出来了,防止了问题的扩散,针对
性的测试,能非常迅速的把潜藏在其中的问题明显的暴漏出来,其实解决问题不是难事,难就难在找到问题
所在,单元测试就是做这个的;
其实单元测试是其他行业最常用的工具,比如:汽车制造公司造出来的马达,肯定是会把马达这一
关键部件拿到单独的环境中去重复测试一遍又一遍的,我相信不会有sb把新马达直接装在汽车上,然后自己
直接上车开上公路做测试的;但偏偏软件开发这行,偏偏大多数人都是直接把汽车开上公路测试的,有些
甚至开上了高速公路...
其次,单元测试在某些情况下要比测试人员好用且更可靠;单元测试的测试用例积累是和代码同样
重要的,甚至比代码重要,代码可以重构,可以换,但测试用列可以照用;说单元测试比测试人员可靠好用
是因为单元测试给代码上了一层保险,或者说上了一份检验程序;且这一程序和流程比起人要可靠的多;实践
中改了某个关键且复杂的地方,往往改的人是有点不安的,因为不敢保证会不会有什么问题,所以往往会提交
给测试人员进行重复白盒测试,即使改动只涉及一行,这一过程不但冗长且枯燥无味且无保障;如果有了单
元测试,简单的进行一次回归测试即可,虽然不敢保证一定没错,但至少心理上安稳了一些;

单元测试的其他好处:
1,开发流程的巨大转变:从此不再是先写代码,然后再编译,然后再测试,而是写一个模块或者
写一个类甚至写一个函数就立马编译,立马测试;从此开发真的就像造一车一样,先造轮子,测试轮子的
质量;造发动机,然后把这个发动机拿出来狠命的测试;

2,单元测试会强迫你去把各个模块解耦,因为耦合的很紧的模块是很难进行单元测试的,一般情
况下,一个普通的程序员在任务很紧的时候很难费劲心思去将代码进行模块化的;当为了单元测试,自己就
会去想方设法将模块解耦,这也算是单元测试的一个副产品吧;

其实这个不应该算是副产品,做单元测试比较多,经验丰富后,写代码之前,心理就会算好,哪些
代码是关键代码,对于这些关键代码,会思考怎么把他们从业务中单独剥离出来(业务代码往往是多变的),
然后为其写专门的单元测;最后写代码,代码会耦合非常小,且结构清晰,加上单元测试的保驾护航,自
然代码质量就非常高了;

3,单元测试能够进行最仔细的最细致的最方便的最全面的测试;只要测试用例足够多,测试路径
可以覆盖所有的边边角角;而这点靠测试人员的黑盒测试基本是不可能的;而且测试用例由自己编写,想怎
么测,想测那条路径,编造测试用例即可;测试人员根本不可能这么多;

呃,有点教科书的味道,讲来讲去单元测试是好处多,知道的人大把,但为什么用的人其实非常少
呢?我想有两点:
1,其实很多人是写业务代码,业务代码有个特点,开始简单,写单元测试反而麻烦;但后面会慢慢
复杂,如果开始架构做的不好,会导致核心代码,算法和业务紧紧的绑在一起了,这时候,想做单元测试也不
太可能了...
2,单元测试需要好的工具;没有好的易用的测试框架,本来写测试代码就显麻烦啰嗦,如果还要
手动去写一堆无关代码就为了测试方便,肯定没人愿意去写;所以很多人明明知道单元测试有用,但他们更
倾向于从客户端到服务器一线的联调...
自从google的 gtest 开源了,发现这真是一件好东西,确实好用,且方便;但我用了几次之后,
发现还是要写一些无关的代码(虽然只有那么10-20行),感觉有点恶心,于是写了个简单的玩意把这些也做
了,以后开源下;

接口测试
单元测试保证了核心代码的质量,那业务代码的质量谁来保证呢?答案是:接口测试;接口测试说
白了就是这个svr的client;svr的是对外服务的,就是接收请求,返回回复;所以接口测试在入口处对svr
进行了校验;这时候找一个实用的简单的易用的client就非常实际了;
一般都会直接用c或者c++写这种client

但用c去写这种 client非常之不实际:
1,  c++ 程序做client非常麻烦,有点杀个鸡还用牛刀的感觉;除了大材小用下,其实还往往
不好用,试下真用牛刀去杀鸡,会顺手吗?
2,  因为client就是要求轻便,能适合修改实时生效运行,这点上,c++程序非常难以做到,如果
为了测试而要不断修改c++ 文件那会令人崩溃;
3,  C++ 这种语言稍显低级,和脚本语言相比表达能力欠缺太多;接口测试要的就是灵活简单,比如
有时测试需要从本地文本加载数据,python或者shell不过几行代码而已,c++去写,我了个去啊,先不说复杂
如果我要改输入文本的名字,那我是不是还要去改c++代码?

解决办法:接口测试极其反对用c++写,python写最好最自然最好不过了;当然用python去和c++ svr
交互有个比较麻烦的地方:通信协议,幸好,有 thriftprotocal buf 这类垮语言的协议工具...

说到python,多说几句,服务器开发人员真的应该学习掌握一种高级脚本语言,不是因为会高级
言就有多炫,主要是用起来顺手;c++用到server,其他的一些辅助程序,独立的程序尽量用高级语言来
完成。
接口测试也有个副产品:client,client可以说是svr的必备,有了client,就可以直接操控和探测
svr了,而不是依赖从客户端过来且经过了一层一层的包,想模拟什么包都是非常简单的事情;自然,从接口
监控svr这一目标也是很简单了...


压力测试
压力测试一般不会用,特别是一些非系统核心模块一般没多大必要,压力测试一般用于关键模块上
线前的压力模拟;当然,压力测试也用于发现系统改动中引入的新bug;为什么要压力测试来发现bug呢?
因为接口测试和单元测试可以称得上白盒测试,测试人员一般可以说是黑盒测试,压力测试也可以说是黑盒
且是一个有点暴力的黑盒测试;

压力测试完全可以建立在接口测试的client上面,只需要加入一些random()之类的随机数据,即可
产生一个压力测试的client;

再说python,压力测试和单元测试一样,需要一些完整的好用的工具;压力测试需要的是高的并发
能力,可能用的最多的压测方式就是:把接口测试的client起50,起100个,这个并发度基本到头了;并发度
并不高;当然一般也就够了,如果追求更好的并发能力,可以采用 python 的 twisted;

在实际项目实践中:接口测试是最普遍的,单元测试依具体情况具体对待;压力测试一般用到的是
非常复杂且易出问题的svr中;底层svr中压力测试也比较普遍;
从实际中发现,单元测试和压力测试做的比较足的svr,质量一般非常高,很少出明显的bug;
当然每种测试都有其局限性,单元测试一般根本不可能包含所有的测试用例,一般是配合压测依赖
上帝(随机掷骰子)“告诉”隐藏很深的的bug;bug发现后,一般会把这种情况加入到单元测试的用例中,随
着时间的推移,项目的迭代,单元测试的用例会越来越丰富越全面,作用也越大;

阅读(4323) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~