51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 36988|回复: 47
打印 上一主题 下一主题

[转贴] 白盒测试实例(实例讲解从需求分析、设计、编码、单元测试、集成测试到构建测试框架)

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2008-9-5 16:03:40 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
目录
1需求说明
2学生的答案
3需求分析
4程序设计
5编码
6单元测试的步骤
7单元测试的尝试
8构建自己的单元测试框架1
9构建自己的单元测试框架2(完整代码)
10集成测试的概念
...


1需求说明



三角形的问题在很多软件测试的书籍中都出现过,问题虽小,五脏俱全,是个很不错的软件测试的教学例子。本文借助这个例子结合教学经验,从更高的视角来探讨需求分析、软件设计、软件开发与软件测试之间的关系与作用。
题目:根据下面给出的三角形的需求完成程序并完成测试:
一、输入条件:
1、 条件1:a+b>c
2、 条件2:a+c>b
3、 条件3:b+c>a
4、 条件4:0<a<200
5、 条件5:0<b<200
6、 条件6:0<c<200
7、 条件7:a==b
8、 条件8:a==c
9、 条件9:b==c
10、条件10:a2+b2==c2
11、条件11:a2+ c2== b2
12、条件12:c2+b2== a2
二、输出结果:
1、不能组成三角形
2、等边三角形
3、等腰三角形
4、直角三角形
5、一般三角形
6、某些边不满足限制
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2
回复

使用道具 举报

该用户从未签到

2#
 楼主| 发表于 2008-9-5 16:11:33 | 只看该作者

2学生的答案

在教学的过程中发现,很多学生一看到这个需求,都觉得很简单,然后立刻就开始动手写代码了,这并不是一个很好的习惯。如果你的第一直觉也是这样的,不妨耐心看到文章的最后。

大部分学生的思路:

1、首先建立一个main函数, main函数第一件事是提示用户输入三角形的三边,然后获取用户的输入(假设用户的输入都是整数的情况),用C语言来写,这一步基本上不是问题(printf和scanf),但是要求用java来写的话,很多学生就马上遇到问题了,java5.0及之前的版本不容易获取用户的输入。  

点评:这样的思路做出来的程序只能通过手工方式来测试所有业务逻辑,而且这个程序只能是DOS界面版本了,要是想使用图形化界面来做输入,就得全部写过代码。

2、业务处理流程的思路用流程图表示如下:



3、C语言代码:

#include<stdio.h>
void main()
{
    int a, b, c;
    printf("please enter three integer:");
    scanf("%d%d%d", &a, &b, &c);
    if(0<a && a<200 && 0<b && b<200 && 0<c && c<200)
    {
        if(a+b>c && a+c>b && c+b>a)
        {
            if(a==b && b==c && a==c)   //这里可以省掉一个判断
            {
                printf("1是等边三角形");
            }
            else
            {
                if(a==b || b==c || a==c)
                {
                    printf("2是等腰三角形");
                }
                else
                {
                    if(a*a+b*b==c*c || a*a+c*c==b*b || b*b+c*c==a*a)
                    {
                        printf("3是直角三角形");
                    }
                    else
                    {
                        printf("4是一般三角形");
                    }
                }
            }
        }
        else
        {
            printf("5不能组成三角形");
        }
    }
    else
    {
        printf("6某些边不满足限制");
    }
}
点评:这样的思路做出来的程序只能通过手工方式来测试所有业务逻辑,而且这个程序只能是DOS界面版本了,要是想使用web或图形化界面来做输入,就得全部写过代码。
回复 支持 反对

使用道具 举报

该用户从未签到

3#
 楼主| 发表于 2008-9-7 12:24:05 | 只看该作者

3需求分析

原文地址(http://blog.csdn.net/aidisheng/archive/2008/09/02/2869377.aspx
    需求分析是后续工作的基石,如果分析思路有问题,后续工作可能就会走向不正确的方向,比如:代码重用性差、难于测试、难于扩展和难于维护等。反而,如果需求分析做的好,对设计、开发和测试来说,都可能是很大的帮助。

看到题目给出的条件达12个之多,粗粗一看,好像很复杂,但仔细分析之后,发现可以把它们分成4组来讨论:

1、 条件1:a+b>c;    条件2:a+c>b;    条件3:b+c>a

这三个表达式有什么特点呢?实际上它们的逻辑是一样的:两个数之和大于第三个数。那么,前面程序的写法就存在逻辑重复的地方,应该把这个逻辑提取到一个函数中。

2、 条件4:0<a<200;  条件5:0<b<200;  条件6:0<c<200

这三个表达式也是同一个逻辑:判断一个数的范围是否在(0, 200)区间内,也应该把这个逻辑提取到一个函数中,去掉重复的逻辑,提高代码的可重用性。

可重用性的好处:比如,现在用户的需求改为了三条边的取值范围要改为[100,400],那么,按前面的思路来说,需要改3个地方,而现在只需要在一个函数里改1个地方,这就是代码重用的好处。

3、条件7:a==b;  条件8:a==c;  条件9:b==c

这三个表达式的逻辑:判断两个数是否相等。也应该把它提取到一个函数中。

我们进一步来分析一下判断是否是等边三角形或等腰三角形的条件:

(1)前面程序的判断是从最直观的方式(a==b && b==c && a==c)(实际上只需要两个表达式成立即可)三条边都相等来判定是等边三角形;(a==b || b==c || a==c)只有两条边相等来判定是等腰三角形。

(2)转变一下思路:给定三个整数,然后用一个函数来判断这三个整数有几个相等,返回相等的个数,如果返回值等于3,那么它是等边三角形,如果返回值是2,那么它是等腰三角形,否则,它是一般三角形(如果不是直角三角形的话)。

4、条件10:a2+b2==c2   条件11:a2+ c2== b2  条件12:c2+b2== a2

这三个条件的处理方式有两种:

(1)跟前面三组分析一样,把相同的逻辑提取到一个函数中,然后三次调用。

(2)根据直角三角形的特点:斜边是最长的,所以我们可以事先写一个函数来找到最长的边,然后把它赋值给c,这样处理之后,只需要一次调用判定(a2+b2==c2)的函数了。
回复 支持 反对

使用道具 举报

该用户从未签到

4#
 楼主| 发表于 2008-9-7 12:39:58 | 只看该作者

4程序设计

原文地址(http://blog.csdn.net/aidisheng/archive/2008/09/02/2869404.aspx

程序设计对于软件的质量和软件实施过程的难易程度起着至关重要的作用。好的设计,即使聘用没什么经验的开发人员都很容易产生出高质量的代码出来;而差的设计,即使是经验很丰富的开发人员也很容易产生缺陷,特别是可重用性、可测试性、可维护性、可扩展性等方面的缺陷。

经过以上的分析,下面来看一下如何设计。在下图中,每个方框都使用一个函数来实现,为了跟用户界面分开,最顶上的函数不要写在main函数中。

把思路用流程图的方式表达出来,不用停留在脑袋里:


具体的函数的调用关系图:

复杂模块triangleType的流程图:
回复 支持 反对

使用道具 举报

该用户从未签到

5#
 楼主| 发表于 2008-9-7 13:07:33 | 只看该作者

5编码

1、Triangle.h

/*
* Copyright (c) 2008, 胡添发(hutianfa@163.com)
*
* 三角形类型判断
*

*/

#include<stdio.h>
#include<String.h>

/*
* 判断一个整数是否在(0, 200)区间内
* 返回值:true-否; false-是
*/
bool isOutOfRange(int i);

/*
* 判断三条边是否合法(即:判断三条边都在合法的范围内)
* 返回值:true-是; false-否
*/
bool isLegal(int a, int b, int c);

/*
* 判断两条边之和是否大于第三边
* 返回值:true-是; false-否
*/
bool isSumBiger(int a, int b, int c);

/*
* 判断三条边是否能够组成三角形
* 返回值:true-是; false-否
*/
bool isTriangle(int a, int b, int c);

/*
* 判断两条边是否相等
* 返回值:true-是; false-否
*/
bool isEquals(int a, int b);

/*
* 求三角形有几条边相等
* 返回值:相等边的数量
*/
int howManyEquals(int a, int b, int c);

/*
* 判断是否满足两边平方之和是否等于第三边的平方
*
*/
bool isPowerSumEquals(int a, int b, int c);

/*
* 判断第一个数是否比第二个数大
*/
bool isGreaterThan(int a, int b);

/*
* 判断是否是直角三角形
*
*/
bool isRightRriangle(int a, int b, int c);

/*
* 判断三角形的类型,返回值:
* 1、不能组成三角形
* 2、等边三角形
* 3、等腰三角形
* 4、直角三角形
* 5、一般三角形
* 6、某些边不满足限制
*/
int triangleType(int a, int b, int c);
2、Triangle.cpp

/*
* Copyright (c) 2008, 胡添发(hutianfa@163.com)
*
* 三角形类型判断
*
*/

#include<stdio.h>
#include<String.h>

/*
* 判断一个整数是否在(0, 200)区间内
* 返回值:true-否; false-是
*/
bool isOutOfRange(int i)
{
    if(0<i && i<200)
    {
        return false;
    }
    else
    {
        return true;
    }
};

/*
* 判断三条边是否合法(即:判断三条边都在合法的范围内)
* 返回值:true-是; false-否
*/
bool isLegal(int a, int b, int c)
{
    if(isOutOfRange(a) || isOutOfRange(b) || isOutOfRange(c))
    {
        return false;      
    }
    return true;
}

/*
* 判断两条边之和是否大于第三边
* 返回值:true-是; false-否
*/
bool isSumBiger(int a, int b, int c)
{
    if(a+b > c)
    {
        return true;
    }
    return false;
}

/*
* 判断三条边是否能够组成三角形
* 返回值:true-是; false-否
*/
bool isTriangle(int a, int b, int c)
{
    if(isSumBiger(a, b, c) && isSumBiger(a, c, b) && isSumBiger(b, c, a))
    {
        return true;
    }
    return false;
}

/*
* 判断两条边是否相等
* 返回值:true-是; false-否
*/
bool isEquals(int a, int b)
{
    if(a==b)
    {
        return true;
    }
    return false;
}

/*
* 求三角形有几条边相等
* 返回值:相等边的数量
* 1:没有边相等 2:只有两条边相等 3:三条边相等
*
*/
int howManyEquals(int a, int b, int c)
{
    int count = 1;
    if(isEquals(a,b))
    {
        count++;
    }
    if(isEquals(b,c))
    {
        count++;
    }
    if(isEquals(a,c))
    {
        count++;
    }
    if(count > 3)  //如果三条边都相等,则count多加了一次
    {
        count = 3;
    }

    return count;
}

/*
* 判断是否满足两边平方之和是否等于第三边的平方
*
*/
bool isPowerSumEquals(int a, int b, int c)
{
    if(a*a + b*b == c*c)
    {
        return true;
    }
    return false;
}

/*
* 判断第一个数是否比第二个数大
*/
bool isGreaterThan(int a, int b)
{
    if(a>b)
    {
        return true;
    }
    return false;
}

/*
* 判断是否是直角三角形
*
*/
bool isRightRriangle(int a, int b, int c)
{
    int max = 0;
    if(isGreaterThan(a, b))
    {
        max = a;
        a = b;
        b = max;
    }
    if(isGreaterThan(b, c))
    {
        max = b;
        b = c;
        c = max;
    }
    return isPowerSumEquals(a, b, c);
}

/*
* 判断三角形的类型,返回值:
* 1、不能组成三角形
* 2、等边三角形
* 3、等腰三角形
* 4、直角三角形
* 5、一般三角形
* 6、某些边不满足限制
*/
int triangleType(int a, int b, int c)
{
    int type=0;
    if(isLegal(a, b, c))
    {
        if(isTriangle(a, b, c))
        {
            int num = howManyEquals(a, b, c);
            if(3==num)
            {
                type=2;
            }
            else if(2==num)
            {
                type=3;
            }
            else if(isRightRriangle(a, b, c))
            {
                type=4;
            }
            else
            {
                type=5;
            }
        }
        else
        {
            type=1;
        }
    }
    else
    {
        type=6;
    }
    return type;
}
回复 支持 反对

使用道具 举报

该用户从未签到

6#
 楼主| 发表于 2008-9-7 13:09:22 | 只看该作者

6单元测试的步骤

白盒测试与黑盒测试的过程和方法是有一些区别的。

单元测试的步骤:

1、  理解需求和设计

理解设计是很重要的,特别是要搞清楚被测试模块在整个软件中所处的位置,这对测试的内容将会有很大的影响。需要记住的一个原则就是:好的设计,各模块只负责完成自己的事情,层次与分工是很明确的。在单元测试的时候,可以不用测试不属于被测试模块所负责的功能,以减少测试用例的冗余,集成测试的时候会有机会测试到的。

举例:

/*
* 判断三条边是否能够组成三角形
* 返回值:true-是; false-否
*/
bool isTriangle(int a, int b, int c);
    测试该函数的时候,只需要测试三条边(在合法的取值范围内的整数)是否能够满足两边之和是否大于第三边的功能,而不需要测试三条边是否在合法的范围(0, 200)之间的整数,因为调用该函数之前,一定要先通过下面函数的检查,要是检查不通过,就不会执行isTriangle函数。

/*
* 判断三条边是否合法(即:判断三条边都在合法的范围内)
* 返回值:true-是; false-否
*/
bool isLegal(int a, int b, int c);
    所以,单元测试主要是关注本单元的内部逻辑,而不用关注整个业务的逻辑,因为会有别的模块去完成相关的功能。

2、  概览源代码

浏览一下源代码,主要任务:

(1)初步检查源代码的编码风格与规范
(2)大致估算测试工作量,比如:需要多少的测试用例、需要写多少的驱动模块和装模块等。
(3)确定模块的复杂程度,初步制定测试的优先级等。

3、  精读源代码

认真阅读和分析代码,主要任务:

(1)理解代码的业务逻辑。
(2)检查代码与设计是否相符,如果详细设计没有该模块的流程图的话,先去画出流程图。
(3)仔细研究逻辑复杂的模块
(4)可以采用一些检查列表来检查程序可能会出现的问题。如果没有检查列表,那么,可以根据程序的特点,有针对性地检查容易出问题的地方(记得把经验总结下来供下次使用)。

4、  设计测试用例

综合运用白盒测试方法(和结合黑盒测试方法)来设计测试用例,包括功能测试、性能测试等,要达到一定的测试覆盖率。在设计测试用例的过程中,流程图或控制流图是分析的好帮手。

5、  搭建单元测试环境

使用XUnit或自己写的框架将有助于单元测试的实施。在这个阶段主要就是写桩模块和驱动模块,第4步所设计的测试用例是通过驱动模块传递给被测试模块的,然后驱动模块想办法获取被测试模块对数据的处理结果,并判定返回的实际结果与测试用例的预期结果是否一致,通过测试框架来记录执行的结果,对于出现的错误,还需要统计错误的信息,供执行完之后分析。

搭建单元测试环境要避免在main函数中使用printf和scanf函数来跟测试人员交互来达到获取测试用例数据的信息。这样的测试还是没有摆脱手工测试方式,效率是低下的。同时,对于测试结果是否通过测试也不要使用printf方式打印被测试函数的返回结果值,避免要人工去检查结果。

6、  执行测试

运行写好的驱动模块完成对被测试模块的测试。

7、  补充和完善测试用例

单元测试也是个循序渐进的过程,可能一开始考虑的不够全面,或预期的覆盖标准太低,需要在测试过程中不断补充测试用例,直到满足要求为止。

8、  分析结果,给出评价

根据测试的结果分析、查找错误的原因,并找到解决的办法。测试结束之后,根据测试过程的数据统计,给出被测试对象评价。
回复 支持 反对

使用道具 举报

该用户从未签到

7#
 楼主| 发表于 2008-9-7 13:10:34 | 只看该作者

7单元测试的尝试

以测试isOutOfRange函数为例,首先知道该函数在整个软件架构中处于最底层(叶子),所以对它进行测试并不需要写桩模块,只需要写驱动模块。要注意的问题是:对于测试结果是否通过测试不要使用printf方式打印被测试函数的返回结果值,否则就需要人工去检查结果了。

  使用边界值的方法可以得到5个测试用例,写的驱动模块代码如下:

  TestTriangle.cpp:
/*
* Copyright (c) 2008, 胡添发(hutianfa@163.com)
*
* 单元测试与集成测试
*
*/
#include "Triangle.h"
/*
* 测试isOutOfRange函数,使用边界值的方法(0,1,5,199,200)
*
*/
void testIsOutOfRange_try()
{   
    if(isOutOfRange(0) == true)
    {
        printf("pass!\n");
    }
    else
    {
        printf("fail!\n");
    }

    if(isOutOfRange(1) == false)
    {
        printf("pass!\n");
    }
    else
    {
        printf("fail!\n");
    }
}



void main()
{
       testIsOutOfRange_try();
}

    小知识:做单元测试的时候,一般不直接在main函数中写所有的测试代码,否则的话,main函数将会非常庞大。正确的做法:针对每个函数分别创建一个或若干个(函数比较复杂时)测试函数,测试函数的名称习惯以test开头。

    写到这里发现重复的代码太多了,而且如果测试用例数量很多的话,对于测试结果的检查也将是很大的工作量。在测试有错误的时候,这样的单元测试结果也很难获得更多关于错误的信息。

    解决问题的途径可以采用cppUnit单元测试框架。不过这里为了让学生能够对单元测试和单元测试框架有进一步的理解,我决定自己写一个类似cppUnit的简单的测试框架。
回复 支持 反对

使用道具 举报

该用户从未签到

8#
发表于 2008-9-11 17:23:21 | 只看该作者
这样就完了?
回复 支持 反对

使用道具 举报

该用户从未签到

9#
发表于 2008-9-18 15:39:32 | 只看该作者
写的挺详细啊

由此可见,做白盒测试是非常费时间的~~很多公司可能都舍不得投入这些资源
5个楼的帖子,只是测试一个方法而已啊~
回复 支持 反对

使用道具 举报

该用户从未签到

10#
 楼主| 发表于 2008-10-7 12:03:20 | 只看该作者

系列文章有了更新

该系列文章有了更新,等有时间的时候再贴到这里来
回复 支持 反对

使用道具 举报

该用户从未签到

11#
发表于 2009-5-25 11:48:03 | 只看该作者
谢谢。不过弄成word的话,会更方便看些。
回复 支持 反对

使用道具 举报

该用户从未签到

12#
发表于 2009-6-20 16:58:50 | 只看该作者
回复 支持 反对

使用道具 举报

该用户从未签到

13#
发表于 2009-7-13 19:03:20 | 只看该作者
写得很详细,拜读了。。。楼主辛苦
回复 支持 反对

使用道具 举报

该用户从未签到

14#
发表于 2009-7-14 11:17:23 | 只看该作者
感谢楼主的分享,体会到了设计的重要性!代码的复用性更强了!
回复 支持 反对

使用道具 举报

该用户从未签到

15#
发表于 2009-12-24 17:14:20 | 只看该作者
下了好好学~sdlkfj%
回复 支持 反对

使用道具 举报

该用户从未签到

16#
发表于 2009-12-26 15:22:35 | 只看该作者
即将开始白盒测试,多谢LZ收集了!
回复 支持 反对

使用道具 举报

该用户从未签到

17#
发表于 2009-12-27 11:03:53 | 只看该作者
这个是因为其中的单元测试中的白盒测试要花费的精力和时间超过其中的投资成本,真的
回复 支持 反对

使用道具 举报

该用户从未签到

18#
发表于 2010-2-2 00:51:44 | 只看该作者
我是来学习的
回复 支持 反对

使用道具 举报

该用户从未签到

19#
发表于 2010-3-2 14:35:20 | 只看该作者
很好,很详细~~
回复 支持 反对

使用道具 举报

该用户从未签到

20#
发表于 2010-3-4 10:32:23 | 只看该作者
回复 支持 反对

使用道具 举报

本版积分规则

关闭

站长推荐上一条 /1 下一条

小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

GMT+8, 2024-11-26 19:21 , Processed in 0.086381 second(s), 27 queries .

Powered by Discuz! X3.2

© 2001-2024 Comsenz Inc.

快速回复 返回顶部 返回列表