posts - 12,  comments - 60,  trackbacks - 3

前段时间公司进行有关测试的培训,集成测试,性能测试,压力测试说了很多。由于本人还处于Coder阶段,只是对单元测试有了些了解。写下来怕以后自己忘记了。都是些自己的看法,不一定准确,欢迎高手指教。

一、 单元测试的概念

        单元通俗的说就是指一个实现简单功能的函数。单元测试就是只用一组特定的输入(测试用例)测试函数是否功能正常,并且返回了正确的输出。
        测试的覆盖种类
        1.语句覆盖:语句覆盖就是设计若干个测试用例,运行被测试程序,使得每一条可执行语句至少执行一次。
        2.判定覆盖(也叫分支覆盖):设计若干个测试用例,运行所测程序,使程序中每个判断的取真分支和取假分支至少执行一次。
        3.条件覆盖:设计足够的测试用例,运行所测程序,使程序中每个判断的每个条件的每个可能取值至少执行一次。
        4.判定——条件覆盖:设计足够的测试用例,运行所测程序,使程序中每个判断的每个条件的每个可能取值至少执行一次,并且每个可能的判断结果也至少执行一次。
        5.条件组合测试:设计足够的测试用例,运行所测程序,使程序中每个判断的所有条件取值组合至少执行一次。
        6.路径测试:设计足够的测试用例,运行所测程序,要覆盖程序中所有可能的路径。
        用例的设计方案主要的有下面几种:条件测试,基本路径测试,循环测试。通过上面的方法可以实现测试用例对程序的逻辑覆盖,和路径覆盖。

二、开始测试前的准备
        
        在开始测试时,要先声明一下,无论你设计多少测试用例,无论你的测试方案多么完美,都不可能完全100%的发现所有BUG,我们所需要做的是用最少的资源,做最多测试检查,寻找一个平衡点保证程序的正确性。穷举测试是不可能的。   所以现在进行单元测试我选用的是现在一般用的比较多的基本路径测试法。

三、开始测试

       基本路径测试法:设计出的测试用例要保证每一个基本独立路径至少要执行一次。

        函数说明 :当i_flag=0;返回     i_count+100
                                当i_flag=1;返回   i_count  *10
                                否则  返回   i_count  *20


        输入参数:int i_count ,  
                            int i_flag
        输出参数: int  i_return; 
        
      
        代码:
         

 1  int Test(int i_count, int i_flag)
 2         {
 3             int i_temp = 1;
 4             while (i_count>0)
 5             {
 6                 if (0 == i_flag)
 7                 {
 8                     i_temp = i_count + 100;
 9                     break;
10                 }
11                 else
12                 {
13                     if (1 == i_flag)
14                     {
15                         i_temp = i_temp * 10;
16                     }
17                     else
18                     {
19                         i_temp = i_temp * 20;
20                     }
21                 }
22                 i_count--;
23             }
24             return i_temp;
25         }



        1.画出程序控制流程图
        
    图例:
  

事例程序流程图:

    

            圈中的数字代表的是语句的行号,也许有人问为什么选4,6,13,8......作为结点,第2行,第3行为什么不是结点,因为选择结点是有规律的。让我们看程序中;第2行,第3行是按顺序执行下来的。直到第4行才出现了循环操作。而2,3行没有什么判断,选择等分支操作,所以我们把2,3,4全部合并成一个结点。其他的也是照这个规则合并,然后就有了上面的流程图。

            2.计算圈复杂度
            
            有了图以后我们要知道到底我们有写多少个测试用例,才能满足基本路径测试。
            这里有有了一个新概念——圈复杂度
            圈复杂度是一种为程序逻辑复杂性提供定量测试的软件度量。将该度量用于计算程序的基本独立路径数目。为确保所有语句至少执行一次的测试数量的上界。
            公式圈复杂度V(G)=E-N+2,E是流图中边的数量,N是流图中结点的数量。
            公式圈复杂度V(G)=P+1 ,P是流图G中判定结点的数量。
            通俗的说圈负责度就是判断单元是不是复杂,是不是好测试的标准。一般来说如果圈复杂度如果大于20就表示这个单元的可测试性不好,太复杂(也许有人觉得无所谓,但是如果你们公司实行了CMMI5的话,对这个是有规定的)。
            从图中我们可以看到,
            V(G)=10条边-8结点+2=4
            V(G)=3个判定结点+1=4
            上图的圈复杂图是4。这个结果对我们来说有什么意义呢?它表示我们只要最多4个测试用例就可以达到基本路径覆盖。

            3.导出程序基本路径。
            
            现在我们知道了起码要写4个测试用例,但是怎么设计这4个测试用例?
            导出程序基本路径,根据程序基本路径设计测试用例子。

             程序基本路径:基本独立路径就是从程序的开始结点到结束可以选择任何的路径遍历,但是每条路径至少应该包含一条已定义路径不曾用到的边。(看起来不好理解,让我们看例子)。
             让我们看上面的流程图:从结点4到24有几条路径呢?
             1 B(4,24)
             2 C,E,J(4,6,8,24)
             3 C,D,F,H,A,B(4,6,13,15,22,4,24)
             4 C,D,G,I,A,B(4,6,13,19,22,4,24)
             还有吗??
             5 C,D,C,I,A,C,E,J(4,6,13,19,22,4,6,8,24)算吗?
            不算,为什么?因为上面的4条路径已经包括了所有的边。第5条路径已经不包含没有用过的边了。所有的路径都遍历过了。
            好了,现在我们有了4条基本独立路径根据独立路径我们可以设计测试用例。

            1 B(4,24)
            输入数据:i_count=0,或者是i_count<0的某一个值。
            预期结果:i_temp=0.

             2 C,E,J(4,6,8,24)
            输入数据: i_count =1;i_flag=0 
            预期结果:i_temp=101.

             3 C,D,F,H,A,B(4,6,13,15,22,4,24)
            输入数据: i_count =1;i_flag=1 
            预期结果:i_temp=10.


             4 C,D,G,I,A,B(4,6,13,19,22,4,24)
             输入数据: i_count =1;i_flag=2     
             预期结果:i_temp=20.
            
            这里的输入数据是由路径和程序推论出来的。而要注意的是预期结果是从函数说明中导出,不能根据程序结构中导出。
            
            为什么这么说?
            让我们看程序中的第3行。
            int i_temp=1;假如开发人员一不小心写错了,变成了int i_temp=0;根据程序导出的预期结果就会是一个错误的值,但是单元测试不出来问题
            那单元测试就失去了意义。

            有人也许会问这么简单的函数就有4个测试用例,如果还复杂一些的怎么办?上面的测试用例还可以简化吗?答案是可以。
            我们来看 路径    1 B(4,24)和   4 C,D,G,I,A,B(4,6,13,19,22,4,24),路径1是路径4的真子集,     所以1是可以不必要的。上图的圈复杂度是4。这个结果对我们来说有什么意义呢?它表示我们只要最多4个测试用例就可以达到基本路径覆盖。所以说圈复杂度标示是最多的测试用例个数,不是一定要4个测试用例才可以。不过有一点要申明的是测试用例越简化代表你的测试越少,这样程序的安全性就越低了。

四、完成测试
            
            接下来根据测试用例使用工具测试NUNIT,VS2005都可以。
            接下来根据测试结果编写测试报告,测试人,时间,结果,用例,是否通过,格式网上一大把,每个公司的格式也不一样就不说了。

------------------------------------------------------------------------------------------------------------------------------------------------------
个人原创,可能有不准确的地方欢迎大家指出。谢谢。

posted on 2007-08-23 09:45 公木子 阅读(11612) 评论(30)  编辑 收藏 网摘 所属分类: .net

FeedBack:
2007-08-23 10:16 | 心有灵犀      
没搞过测试,学习下
  回复  引用  查看    
2007-08-23 10:16 | 永红      
先收藏。
  回复  引用  查看    
2007-08-23 12:41 | Evernory      
不错。最近也在研究单元测试
  回复  引用  查看    
2007-08-23 14:11 | BlueMountain      
收藏
  回复  引用  查看    
2007-08-23 14:30 | 无处坏      
不错。最近也在研究单元测试
  回复  引用  查看    
2007-08-23 14:54 | 追求卓越      
有一点疑问:
单元测试和白盒测试不是一个概念.
白盒测试是一类测试方法,是能够看到代码的测试.比如覆盖测试等等..
而单元测试是一个测试阶段,在单元测试中会用到大部分白盒测试的方法.

  回复  引用  查看    
#7楼[楼主]
2007-08-23 15:37 | 公木子      
没错,单元测试和白盒测试不是一个概念. 我写在一起并没有别的意思,是说单元测试属于白盒测试的一种。

白盒测试和黑盒测试是同一级别的概念,区别在于黑盒测试方法通过程序的规格说明来识别测试用例,白盒测试根据呈现的内部代码结构(分支,循环,条件)来识别测试用例。

  回复  引用  查看    
2007-08-23 15:55 | orichisonic[未注册用户]
有一本单元测试之道,挺不错的,我这里只有英文版
  回复  引用    
2007-08-23 17:05 | Mirricle      
实际开发中,涉及算法的东西比较少,比较多的是数据库的读写
比如GetCustomers GetCustomerById UpdateCustomer DeleteCustomer等等,这种东西怎样做单元测试呢?

无输入,无输出的方法又该怎样做单元测试

WebService该怎样做单元测试,WebService调用其他WebService又该在那样测

  回复  引用  查看    
2007-08-23 23:46 | Reeezak      
说实话,受益匪浅~~~

一直知道我不会测试,但没有想到的是,我居然根本就不会测试~~~

看来要想想办法了~~~

我也需要一个能够学习的环境~~

PS:非常感谢博主的这篇blog,不仅让我学到了知识,还真正的明白了自己的无知

  回复  引用  查看    
2007-08-24 11:47 | flood[未注册用户]
确实不错,期待lz能有一个比较深入的介绍,例如测试框架。Form窗体的用户行为的模拟,数据库测试等等
  回复  引用    
#12楼[楼主]
2007-08-24 13:40 | 公木子      
@Mirricle
无输入,无输出的方法又该怎样做单元测试

我也问过那个培训老师,他的回答是如果单元无输入,无输出逻辑简单,而且里面都是调用的类库什么的。不需要坐单元测试,单元测试是程序测试的最开始阶段。这些简单的函数如果有问题一般会在黑盒测试(集成测试)中暴露出来。同时他也说不是什么函数都要进行单元测试。单元测试是很花时间的。很浪费人力和物力,增加了软件的成本。要综合的平衡考虑。

  回复  引用  查看    
#13楼[楼主]
2007-08-24 13:41 | 公木子      
@Reeezak
我也是初学者,大家一起交流,共同进步。

  回复  引用  查看    
#14楼[楼主]
2007-08-24 14:01 | 公木子      
@flood
Form窗体的用户行为的模拟,数据库测试 暂时还没有研究过。上面的都属于自动化测试的范围。我想学还没机会。这些测试都不是普通的测试人员可以做到的了。必须配合工具最有名的就是IBM的Rational Robot 等,不过这些东西,不是一个小公司能受得了的。就算你装了一套盗版的Rational Robot 要招几个真正会这个东西的人,成本很高。我还没有机会接触。 有兴趣LS可以自己研究一下。

  回复  引用  查看    
2007-08-24 17:48 | 空明流转的马甲[未注册用户]
单元测试一般都基础组件的测试。。。至少我是这么应用的。
  回复  引用    
2007-09-27 09:34 | gg[未注册用户]
好得很 支持!
  回复  引用    
2007-09-27 09:38 | gg[未注册用户]
确认一下: V(G)=10条边-8结点+2=4;V(G)=E+N+2是前面的为准吧?
  回复  引用    
#18楼[楼主]
2007-10-09 16:05 | 公木子      
@gg
@gg
--引用--------------------------------------------------
gg: 确认一下: V(G)=10条边-8结点+2=4;V(G)=E+N+2是前面的为准吧?
--------------------------------------------------------
应该是V(G)=E-N+2已经修改,谢谢

  回复  引用  查看    
2007-11-28 10:19 | BOYOW[未注册用户]
最近也在研究﹐我認為單元測試﹐不只是測試代碼的正確性﹐而是測試代碼是否符合設計的功能,不知大家認同不
  回复  引用    
2007-12-11 17:04 | AKgg[未注册用户]
这里的输入数据是有路径和程序推论出来的。而要注意的是预期结果是从函数说明中导出,不能根据程序结构中导出。


没明白

  回复  引用    
#21楼[楼主]
2007-12-26 15:44 | 公木子      
--引用--------------------------------------------------
AKgg: 这里的输入数据是有路径和程序推论出来的。而要注意的是预期结果是从函数说明中导出,不能根据程序结构中导出。


没明白
--------------------------------------------------------
就是说你的测试用例子。不能根据程序的逻辑来判断,要根据模块开发卷宗的函数说明来判断。

  回复  引用  查看    
2008-04-25 10:44 | deeloo      
写的非常好!收藏了
  回复  引用  查看    
2008-07-15 16:20 | 挑刺的人[未注册用户]
这个例子不太严谨,不会写测试用例的人最好不要被误导,仔细研究下这个例子,觉得非常烂
  回复  引用    
2008-10-14 11:40 | 有疑问?[未注册用户]
还是没有看明白,LZ有时间可以再细致一些嘛,写的应该是一个测试的程序,但是没有用到原程序,一个单独的测试程序,可以测试出原程序的错误吗?
  回复  引用    
2008-10-15 12:22 | 希望博主能看见,并修正不明之处[未注册用户]
博主的描述有的地方有误请确认,免得把大家搞糊涂了
不明之处1:
明明前面的简介是这样
函数说明 :当i_flag=0;返回 i_count+100
当i_flag=1;返回 i_count *10
否则 返回 i_count *20
但楼主的给出的代码截图却是这样:
if (0 == i_flag)
7 {
8 i_temp = i_count + 100;
///当i_flag=0;返回i_count+100 这个没问题
9 break;
10 }
11 else
12 {
13 if (1 == i_flag)
14 {
15 i_temp = i_temp + 10;
///
当i_flag=1;返回 i_count *10问题来了,到底是
i_temp = i_temp * 10 还是i_temp = i_count * 10,
还是i_temp = i_temp + 10 被博主搞晕了???
///
16 }
17 else
18 {
19 i_temp = i_temp + 20;
///否则 返回 i_count *20
疑问同上
20 }
21 }

不明之处2:
还有在设计测试用例时
1 B(4,24)
输入数据:i_flag=0,或者是i_flag<0的某一个值。
预期结果:i_temp=0.
但你给的程序截图明明是:while (i_count>0),怎么会关i_flag的事,根据你的描述我推断是否应该是这样的:
1 B(4,24)
输入数据:i_count=0,或者是i_count<0的某一个值。
预期结果:i_temp=0.

  回复  引用    
2008-10-15 12:26 | 希望博主能看见,并修正不明之处[未注册用户]
不过还是很感谢博主提供这方面的学习资料,不错,对于新人来说浅显易懂,相关概念描述的很清楚,还有一个地方希望博主说明下
公式圈复杂度V(G)=E-N+2,E是流图中边的数量,N是流图中结点的数量。
公式圈复杂度V(G)=P+1 ,P是流图G中判定结点的数量。

这2个复杂度以哪个为准???都可以还是怎样??

  回复  引用    
2008-12-17 11:50 | lvj[未注册用户]
想知道 就单元测试中那些函数无需做单元测试
  回复  引用    
2009-03-23 16:47 | 王晓梦[未注册用户]
@orichisonic
可以把这本书发给我 吗"英文版"的,谢谢。
我的邮箱:hupo1114@163.com

  回复  引用    
#29楼[楼主]
2009-05-17 00:35 | 公木子      
--引用--------------------------------------------------
希望博主能看见,并修正不明之处: 博主的描述有的地方有误请确认,免得把大家搞糊涂了
不明之处1:
明明前面的简介是这样
函数说明 :当i_flag=0;返回 i_count+100
当i_flag=1;返回 i_count *10
否则 返回 i_count *20
但楼主的给出的代码截图却是这样:
if (0 == i_flag)
7 {
8 i_temp = i_count + 100;
///当i_flag=0;返回i_count+100 这个没问题
9 break;
10 }
11 else
12 {
13 if (1 == i_flag)
14 {
15 i_temp = i_temp + 10;
///
当i_flag=1;返回 i_count *10问题来了,到底是
i_temp = i_temp * 10 还是i_temp = i_count * 10,
还是i_temp = i_temp + 10 被博主搞晕了???
///
16 }
17 else
18 {
19 i_temp = i_temp + 20;
///否则 返回 i_count *20
疑问同上
20 }
21 }

不明之处2:
还有在设计测试用例时
1 B(4,24)
输入数据:i_flag=0,或者是i_flag&lt;0的某一个值。
预期结果:i_temp=0.
但你给的程序截图明明是:while (i_count&gt;0),怎么会关i_flag的事,根据你的描述我推断是否应该是这样的:
1 B(4,24)
输入数据:i_count=0,或者是i_count&lt;0的某一个值。
预期结果:i_temp=0.

--------------------------------------------------------
不好意思今天才看到你的留言。是我的测试代码有问题,已经修正

  回复  引用  查看    
#30楼[楼主]
2009-05-17 00:36 | 公木子      
--引用--------------------------------------------------
希望博主能看见,并修正不明之处: 不过还是很感谢博主提供这方面的学习资料,不错,对于新人来说浅显易懂,相关概念描述的很清楚,还有一个地方希望博主说明下
公式圈复杂度V(G)=E-N+2,E是流图中边的数量,N是流图中结点的数量。
公式圈复杂度V(G)=P+1 ,P是流图G中判定结点的数量。

这2个复杂度以哪个为准???都可以还是怎样??
--------------------------------------------------------
只要正确的区分清楚了判定结点,边,结点两个公式计算的结果应该相等

  回复  引用  查看    



发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 862737




相关文章:

相关链接:
<2007年8月>
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678


当前在线人数: online人在线

与我联系

搜索

 

常用链接

留言簿

我参与的团队

随笔分类

随笔档案

文章分类

收藏夹

最新评论

阅读排行榜

评论排行榜