51Testing软件测试论坛

标题: 单元测试的桩函数问题 [打印本页]

作者: cdq1010    时间: 2007-5-20 21:23
标题: 单元测试的桩函数问题
在我们课本第一册单元测试后有个课后习题:

函数A判断X和Y的大小来运行函数B或函数C
函数B返回X加Y的值
函数C返回X减Y的值


例如:我们对函数A和函数B进行测试时,要写一个桩函数。

问题1:我们要写的这个桩函数是不是就是函数C?

问题2:如果不是,那么我们是不是还要先对这个桩函数进行测试呢?
作者: jane_li    时间: 2007-5-20 22:59
我认为不是
我们设计桩函数时一般要根据单元的LLD,针对不同的输入得到不同的输出。也就是把自己设计的用例写成桩单元就行
需不需要进行测试是看你采用的什么测试策略是自顶向下还是自底向上
作者: zhangchen    时间: 2007-5-21 11:24
答问题1:首先应搞清桩的概念。我们要写的这个桩函数不是函数C,而是为函数C写桩,来代替函数C.
我们对函数A和函数B进行单元测试时其实是为了验证函数B的正确性,写桩是为了更好的定位错误。
作者: cdq1010    时间: 2007-5-21 17:30
那么请问这个桩函数就该怎样写?能否贴出具体的内容?
作者: gzj_06    时间: 2007-5-21 20:18
当然不是函数C,而是用来替代C的函数,这个函数可以说是不用测试的,在编写时就要确保没有问题的,因为这个函数比较简单,所以它的正确性容易保证

测A函数时,要写两个桩函数代替B和C,具体写桩是要根据用例来写的
作者: gzj_06    时间: 2007-5-21 20:45
具体题目我忘了,假如X>Y时就调用加法函数B,并且你设计了如下两个用例:
Test Case 1: x=2,y=1 Expected output value:3
Test Case 2: x=1,y=-1 Expected output value:0
那么用来代替B函数的桩函数就可以这么写:
int stub_Add(int x, int y)
{
    if((x==2)&&(y==1))
       return 3;  
    else if((x==1)&&(y==-1))
        return 0;
     else
        return 100;
}

[ 本帖最后由 gzj_06 于 2007-5-22 07:31 编辑 ]
作者: Jean.zhou    时间: 2007-5-21 20:48
测试函数A,则要编写函数B和函数C的桩函数,就是用桩函数代替函数B和函数C.
测试函数A和函数B,则要编写函数C的桩函数,就是用桩函数代替函数C.
如果X-Y=-1
则可以写成:
int stub_sub(int x,int y) /*桩函数*/
{
  if((1==x)&&(2==y))
    return -1;
  else
    return 888;
}
作者: seifer1754    时间: 2007-5-21 21:21
A         
/  \
B   C

int Function_A(int x , int y)
{
   if( x >= y)
   return add_B(x,y);
  else
   return sub_C(x,y);
}

设计测试用例
               case 1          case2
输入       x=1, y=2      x=2, y=1
预期输出    -1                  3


设计桩函数

int stub_add_B(int x, int y)
{
   if ( (2 == x) &&(1 == y) )
     return 3;
   else
     return 9999; //返回 9999 是为了能够明显的看出程序的输出结果异常
}

int stub_sub_C(int x, int y)
{
   if ( (1 == x) && ( 2 == y) )
      return -1;
   else
     return 8888;   //输出8888 也是为了能够看出程序有明显的异常
}

设计驱动函数

void drive_A()
{
   int result = 0;
   result = Function_A(1,2);
   if ( -1 == result)
    printf("Case1 Pass! \n");
   else
    printf("Case1 Fail! \n");

   result = Function_A(2,1);

   if ( 3 == result)
   printf("Case2 Pass! \n");
   else
   printf("Case2 Fail! \n");
}
作者: benz    时间: 2007-5-21 22:07
同意8楼,b和c应该是属于被a调用,而不是桩~
最直接的做桩就是直接输入数值进行判断~楼上讲的很明白~
作者: gzj_06    时间: 2007-5-22 08:14
如果采用自顶向下的单元测试策略,那么要先测A函数,由于A没有被任何函数调用,并且如果A可以自己驱动的话(我这里都是基于这一假设,如果不能驱动,那么也要写驱动,请参考8楼),那么就不需要写驱动函数,但A要调用B和C,所以必须要写分别用来代替B和C的桩函数,具体内容参见8楼,8楼写的很详细;然后接着测B,此时A已被测试通过,所以直接可以用A作为驱动,但C必须要改为桩;最后测C,由于此时A和B均已测试通过,所以仍然用A作为驱动,而B也可以直接使用,不需要桩

如果采用孤立的单元测试策略,那么测这三个函数没有先后顺序,测A时不要驱动,但要两个桩,测B和C时都是只要写驱动即可,不需要桩,因为它们没有调用别的函数

如果采用自底向上的单元测试策略,那么要先测B或C,此时的方法与孤立策略相同,测A时,由于B和C均已测试通过,所以不需要桩,直接使用即可

[ 本帖最后由 gzj_06 于 2007-5-22 08:31 编辑 ]
作者: cdq1010    时间: 2007-5-22 12:49
标题: 明白了
谢谢各位的指教
我明白了桩函数和驱动函数都是根据我们设计的测试用例,
把具体的数值代入程序中,
然后查看运行结果是否准确
作者: hbjfx    时间: 2007-5-22 19:48
sdlkfj3
作者: lifego    时间: 2007-5-22 21:24
这个还是偶们的作业呢,只是交上去也没评点...期待老师的指教.sdlkfj3
作者: YT0313    时间: 2007-5-23 12:24
这道题我做了,也问了老师,现把我做的传上来,以便大家交流与沟通!
作者: seifer1754    时间: 2007-5-23 12:30
设计桩和驱动还有从测试策略方面来考虑。
我是采用由顶至下的策略来测试的,因为 A 调用了 B和C ,所以要为 B,C 设计桩,
如果要采用由底至上的策略来测试,那么首先要对 B,C 分别进行孤立测试,
然后用函数A 作为驱动来测试,在测试A的时候,就可以直接调用B,C了,这样可以减少桩的开发。
基本理论就是这些,具体情况还有根据自己工作中的一些规定和需要灵活进行。
作者: 三碗猪脚    时间: 2007-5-24 21:11
sdlkfj3
作者: hyq828    时间: 2007-5-25 13:45
不错
作者: jiangyuetian    时间: 2007-5-30 09:20
函数B和函数C进行孤立测试,是不是只要写驱动呢?
作者: qianlilv    时间: 2007-5-30 17:51
好东西啊
作者: seifer1754    时间: 2007-5-30 19:44
原帖由 jiangyuetian 于 2007-5-30 09:20 发表
函数B和函数C进行孤立测试,是不是只要写驱动呢?



如果函数B和C,只是被其他函数调用,那么B和C就是最底层的函数,所以我们在
测试B和C的时候,就只需要针对B,C的输入条件进行用例设计,针对B,C的输出
条件进行结果判断。
当然,这个例子只是一个最理想情况下的,最简单的例子了,在实际的工作中,软
件函数的调用关系要复杂的多。
根据开发平台的不同,单元测试的框架也有很大的差别。所以在51testing,需要重
点掌握测试的基本理论和方法,这样在进行用例设计的时候才能够尽可能多的覆盖
所有条件。
作者: lzyk9999    时间: 2007-5-30 21:30
看完次帖,对驱动和桩的概念越发明白了,多谢楼上的各位师兄们,谢谢!
作者: stephany    时间: 2007-6-1 12:17
请教~~!


举个B的桩函数的例子.

int stub_add_B(int x, int y)
{
   if ( (2 == x) &&(1 == y) ) //


写桩函数时,需要用具体数值代入,如果用例为多个时,是否需要每次在此处将x,y的值手动做更改.
     return 3;
   else //
在此处为何需要用else,因为A的驱动已做到返回异常情况。如果程序在此处会出现异常情况,有可能会在哪里出现问题?请举个例子
     return 9999; //返回 9999 是为了能够明显的看出程序的输出结果异常
}

作者: seifer1754    时间: 2007-6-1 21:20
如果采用自顶向下的方法来测试,开发桩函数确实需要根据用例的设计来开发,
由此可见,开发桩函数是非常耗费工时的;所以一般企业都习惯采用自底向上的
方法来进行测试,这样可以避免桩函数的开发,而对于驱动的开发相对来说要轻松
一些,毕竟一个驱动可以采用循环来包含所有的测试用例。

至于这个桩函数B的例子,让它返回9999,是为了能够返回一个与正确输出数值3 有很大
差别的数字 而设计的。
如果根据用例设计了两个桩函数

int stub_add_B(int x, int y)
{
if((2 == x)&&(1 == y))
return 3;
else
return -1;
}

int stub_sub_C(int x, int y)
{
if((1== x)&&(2 == y))
return -1;
else
return 3;
}

那么在执行用例的时候,如果调用了错误的桩函数,
对于驱动 void drive_A() 就无法正常的打印信息。

所以,在设计桩函数的时候,返回的错误值最好选择一个不可能出现的数字,
这样进行错误判断的时候才能够更明显。

另外,需要指出的是,我们对函数A设计驱动和桩,其目的是为了测试函数A,
是为了能够测试A的条件判断是否正确,所以针对 x >=y 这个判定条件,我们
设计3个用例,(也就是说,设计3个桩函数)就能够覆盖了。
我们不是要测试B和C的功能,对于B,C 我们会单独测试。
一定要清楚我们测试的是哪一个函数,不要认为是将A,B,C三个函数一起测试。

不知道我将的是否清楚,见笑见笑。
作者: jane_li    时间: 2007-6-1 22:42
讲的很好啊
作者: Yzzz    时间: 2007-6-2 10:57
seifer1754~讲的太好了~sdlkfj2 ~明白的很~DDD
作者: qubao0451    时间: 2007-6-10 15:07
标题: 456
我要好好学习学习~
作者: lhjtc8257    时间: 2007-8-1 16:58
问题1:我们要写的这个桩函数是不是就是函数C?

问题2:如果不是,那么我们是不是还要先对这个桩函数进行测试呢?


不是
桩函数是:在主函数未测试前,为了保证正确,模拟子函数

如果孤立测试的话,就单独测试3个函数A,B,C

自底向上测试,设置驱动函数分别测试函数B,C  再使用A,B,C一起测试

自顶想下测试,设立两个桩函数模拟B,C函数的功能




欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2