|
Visual Unit可以从http://www.KaileSoft.cn下载,资料很全的,包括视频教程。
测试环境很难模拟实际运行,那就更需要单元测试了,因为这样的话,系统测试是不可能做得很充分的,而单元测试的测试对象是类或函数,测试时与其他代码隔离,本来就不考虑实际运行环境。
访问私有或保护的成员,这个问题不大,Visual Unit可以轻松解决。
要真正做单元测试,软件耦合度高是一个大问题,要解决这个问题,很多人都会想到打桩,最好是自动打桩,但是我认为,靠打桩来解决耦合度高只是一个美好的愿望,在实际工作中意义不大,我这种说法,我想你不会同意,大多数人都不会同意,下面举一个例子来说明:
假设我现在要测试一个排序程序:
void Sort(int* list, int count)
{
.....
Swap(a1, a2);
.....
}
如上,排序程序通常需要交换两个数据,一般会另外写一个函数来实现这个功能,如上面的Swap()。现在我假设函数Swap会产生耦合的问题,想打桩来隔离它,那么很多工具都可以做到,但工具生成的桩通常只是一个空函数,这样的话,调用这个Swap函数的桩函数时并没有完成两个数据交换,那么,Sort函数的功能就完成不同了,根本就没有实现排序,你怎么测试它?当然,还可以用两种办法来改进桩代码,一是人工在桩中添加代码,但是要使桩的功能和原来函数的功能一样,等于要重写代码,桩也就没有意义了,第二种方法是由工具将原来的代码抽出来,拷贝到桩中,在这个例子中,这种方式是可行的,因为Swap只是一个很简单的函数,没有涉及到其他代码,但在实际工作中,情况远比这个复杂,把一个函数的代码拷到另一个地方,通常都是不能工作的。
一个函数,它所调用的函数往往具有复杂的功能,不是随便可以替代的,所以,我认为通过工具打桩来解决耦合度高是不现实的,解决这个问题的现实途径是重构。重构看起来麻烦,实际做起来不见得很难,我在这里贴一段Visual Unit官方网站中的文字,更详细的信息请浏览Visal Unit的帮助和教程:
单元测试如何改良项目代码的整体结构?
具有良好整体结构的代码,应该符合“低耦合”的特性,形象的说,就是“各家自扫门前雪、不管他人瓦上霜”,每一个函数、每一个类、每一个模块,都应该只做自己该做的事,不要把应该由“其他人”做的事扯进来。具有良好整体结构的代码就具有“可测性”,否则就不具有“可测性”。
系统分析和架构设计做得比较好的项目,所实现的代码一般具有比较好的整体结构,应该首先在这方面下功夫。另一方面,单元测试是“隔离”的测试,可以说,“隔离”是单元测试的最基本特性,不能“隔离”的代码,单元测试也就难于进行。通常,“低耦合”的代码可以隔离,具有不当的高耦合特性的代码难于隔离,因此,单元测试能够及时地发现不当耦合,推动代码重构,从而保证了代码具有良好的整体结构。
具体来说,如果代码包含不当耦合,当这些代码加入测试工程后,会产生编译错误,或者需要打桩才能测试,从而将不当耦合暴露出来。发现问题后,重构代码、消除不当耦合一般不难,消除不当耦合后,单元测试就可以顺利进行了。
下面是几种典型的不当耦合:
把代码写在界面类中
问题:如果把业务代码写在界面类中,测试时把界面类加入测试工程,会产生编译错误。
解决:把业务代码独立出来,写到相应的实体类中,对这些实体类进行测试。界面类只负责数据的显示和接受用户的输入,具体的计算由实体类负责。
说明:把业务代码写在界面类中,这些代码将很难管理和维护,复用就更谈不上了,这是一定要避免的。
实体类混合了边界代码
问题:例如,一个表示用户的类CUser,它的对象的数据保存在数据库中,如果在CUser类中直接读写数据库,就是实体类混合了边界代码,这也是一种不当耦合,测试CUser类时要察看数据库,或者要打桩,甚至会产生编译错误。
解决:把执行数据库操作的代码写到CDatabase类中,CUser类和CDatabase类没有任何关联,由界面类或用于协调各对象工作的控制类来操作这两个类的对象进行数据读写,现在对CUser类的测试就完全和数据库无关了。
说明:经过重构后,代码的可扩展性、可复用性都有了很大提高,也便于进行单元测试和将来的维护。
无意中形成了高耦合
问题:例如,CMyClass类中一个函数中有这样的语句:
CDemoApp* pApp = (CDemoApp*)AfxGetApp();
UNIT var = pApp->GetXXX()->Getxxxx();
由于CDemoApp是工程的最高层类,可能跟工程中的所有类关联,这两行代码就造成被测试对象跟工程中的所有类耦合。耦合具有扩散性,纵向来说,CMyClass类的所有子类也可能跟工程中的所有类关联,横向来说,所有使用了CMyClass类的类,也可能跟工程中的所有类关联,从而形成了盘根错节的关系。这种问题往往很难发现,但把代码加入测试工程后,一般来说是通不过编译的,从而使问题暴露。
解决:修改被测试代码,去除耦合。把需要从pApp指针中取得的数据改为由参数传进来,这两行代码移到客户程序(即调用被测试函数的代码)中,如果客户程序也是实体类,则继续往上移,直到界面类。
说明:这类无意中形成的耦合非常常见,一般的代码审查、静态扫描都很难发现这类问题,但把代码加入测试工程后,编译器却能轻松发现。这类问题只要及时发现了,消除并不难,经过简单的代码重构后,就可以有效地提高代码质量,特别是提高代码的可复用性,也使单元测试可以顺利进行。
开发工具生成的代码形成了不当耦合
有时候,开发工具生成的代码也形成了不当耦合,例如,VC6.0生成的类代码中,源文件会添加下面的代码:
#include "ProjectName.h" //ProjectName是工程名
如果在另一个不同名的工程中复用代码,这一行就会产生编译错误。进行单元测试时,这一行形成的不当耦合也可能会导致编译错误,因此应删除它。
[ 本帖最后由 dellfox 于 2006-7-18 12:10 编辑 ] |
|