Nunit单元测试

Nunit单元测试

计算机专业     薛会萍     S10111295

摘要:随着软件规模的不断扩大和复杂性提高,测试环节越来越受到重视。本文首先描述软件测试的基本知识,着重叙述单元测试,然后介绍一些单元测试的工具,最后再使用NUnit进行一些实践测试,并进行小结。

关键字:软件测试        单元测试         NUnit

正文

 

1.       软件测试

1983年,IEEE定义软件工程为“软件工程是开发、运行、维护和修复软件的系统方法”。这个定义强调了软件工程是一种系统方法,而不是个人技巧。在软件的生命周期中使用一套技术,来完成各个阶段的详细任务,这套技术的集合成为软件工程方法学。目前使用最广泛的软件工程方法学,分别是传统方法学和面向对象方法学,他们都包含三个要素:方法、工具和过程[1]

犹如课程学习的时候要进行单元测试、综合测试,或者比较正式的期中考试和期末考试,软件开发的过程也是如此。软件的测试贯穿于软件的整个生命周期,从需求阶段的确认需求分析,再到设计和编码阶段的功能完整、代码不出错,以及最后的集成部署,都离不开软件测试。

1             软件测试与各个开发阶段的关系

 

如图1所示,软件工程的过程包括了需求分析、概要设计、详细设计、编码、单元测试、集成测试、确认测试等过程,当然这只是常见的一种,目前的分法有很多种,但是大致的也是这个样子。单元测试对应的是编码和详细设计阶段,也就是说,单元测试检验的对象是编码和详细设计阶段的工作成果,在此步骤完成后,再进行集成测试和确认测试。集成测试和确认测试的步骤也单元测试类似,都有自己的对象,这里不再赘述。

软件测试的步骤也可以如图2所示,很多个单元测试完成之后,当然是各个模块了,才能进入集成测试。这点很容易理解,试想一下,如果不能保证各个子模块的正确性和完整性,就进行集成测试,必然导致集成之后的产品难以如我们希望地工作。这就好比我们要建造一幢楼房,可是选择了低质量的砖块和楼板,那么这个后果真实难以想象的。同理,对于集成测试之后的产品,再结合设计时候使用的信息,就可以进行确认测试了。既然我们从需求分析、设计、编码一步一步艰难地走过来,现在终于到了测试的时候,为什么还要在集成测试的时候加入设计信息呢?而且,按照图2所示,后面还要加入需求分析?这是因为:我们难免会偏离方向!有可能,在进行详细设计的时候,和最初的需求有所出入,也有可能,我们在编码的时候无意中偏离了总体设计的方案。所以,为了保证软件与客户的需求尽量一致,我们需要一步一步地核实各个阶段的工作。做到项目完整,尽量没有疏漏,满足客户的期望。都不希望在产品交付的时候,客户说:“这不是我想要的。”

2             软件测试的步骤

 

         传统的软件生命周期分为需求分析、设计、编码、测试和维护几个阶段,这就是著名的“瀑布模型”,它是最简单的一种软件开发过程。软件开发过程模型还有很多中,诸如原型模型、快速应用开发模型、螺旋模型、增量模型和迭代模型、构建组装模型和并发模型等等。这些开发模型并不是本文要讨论的内容。

         从本质上来说,软件测试是为了保证软件质量,软件质量就是客户的满意度。从不同的角度,软件测试可以分为不同的种类:

1)         从是否需要执行被测软件的角度,分为静态测试和动态测试。

2)         从测试是否需要针对系统的内部结构和具体实现的算法的角度,分为白盒测试和黑盒测试。

3)         按照测试的对象,分为面向开发的单元测试、GUI和捕捉/回放测试、基于Web的应用测试、负载和性能测试、数据库测试等等。

4)         其他的测试方法还有恢复测试、安全测试、兼容性测试等等。

文献[2]提出了非常详细的测试分类,了解软件测试的分类是重要的,这有助于理解工作内容和沟通团队成员。文献[3]提出了基于渗透、基于故障树的多种软件安全性的测试方法。

 

2.       单元测试

什么是单元测试?

单元测试的定义有很多种:

       单元测试是开发者编写的一小段代码,用于检验被测代码的一个很小的、很明确的功能是否正确。

       通常而言,一个单元测试是用于判断某个特定条件(或者场景)下某个特定函数的行为。

       执行单元测试,是为了证明某段代码的行为确实和开发者所期望的一致。

单元测试的对象是程序系统中的最小单元-----模块或者称为组件。这个过程是在编码阶段进行的,主要使用白盒测试方法,根据程序的内部结构设计测试用例。多个模块可以并行地测试。所谓最小单元就是有明确的功能定义、性能定义、接口定义,而且可以清晰地与其他的单元区分开来。单元测试通常使用的方法有逻辑结构测试、路径测试、代码走读、静态分析、动态分析等。单元测试的目标是:高内聚、低耦合,确保模块被正确地编码。最终期望的结果是:模块的行为与开发者期望一致。换句话说,这就是开发者对于单元测试的终极目标。当然,作为终极目标,它应该是有依据的,这里的依据就是详细设计说明书。

 

单元测试的任务:

我们来具体分析一下单元测试的任务,在这个阶段,到底要做什么?为了达到上面说的终极目标,我们需要做以下工作:

1)         模块接口测试。

有数据输入模块,也有数据输出模块,在这个前提下才能进行测试。就是说,要进行测试,首先模块是可以测试的。

2)         模块局部数据结构测试

以保证模块中的数据(也可能是临时存储的),在模块执行的过程中,是完整的、正确的。常见的错误有变量未初始化、地址异常、上溢下溢、类型声明错误等。

3)         模块边界条件测试

就是测试模块中使用的数据的上界和下界,这对于边界测试和设计测试用例是非常重要的。

4)         模块中所有独立执行通路测试

验证每一条路都可执行的,并且每一条路至少执行一次。例如,if判断之后,是执行接下来的又一次判断或者执行语句,还是返回。

5)         模块的各条错误处理通路测试

尽量预见各种出错可能条件,并预设各种错误处理通路。

 

使用单元测试有什么好处:

       不但会使工作轻松地完成,而且会使设计变得更好,甚至大大减少花在调试上面的时间。

       行为与期望一致

       代码可以依赖

错误和不可以依赖的代码,给接下来的工作会造成很严重的负面影响。软件测试的目的之一就是尽可能早地发现软件中存在的问题,从而降低软件的成本。就这个测试过程来说,单元测试是最基础的,也是测试的第一步,所以它的重要性不言而喻。一个好的单元测试应该做到:自动化、彻底的、可重复、独立的、专业的。也就是:使用工具,不完全依靠人力劳动;不留后患,彻底检查;可以进行多次检测,值得推敲;不依赖其他模块进行本模块的测试;具有一定的专业性。

 

误区,通常,会有人提出这样的想法:

        我已经严格按照详细设计的文档进行了编码,为什么要做单元测试?太花时间了。我是严格按照文档做的!

        我是做开发的,干嘛要做测试?那不是我的工作。

        我做测试,那测试人员怎么办?

        我写的这些代码已经编译通过了,没有必要进行测试了

        反正测试也是测试这个模块,就算正确了,等到系统集成之后,还不知道会发生什么呢。

关于这些问题的解答,可以参考文献[4]。那里面给出了非常详细生动的描述和解释。作者已经读过那本书,在这里不直接给出答案,给读者留些思考的空间。

本文后面叙述的NUnit实践,也是得益于此书介绍的方法,在这里表示非常的感谢!

 

3.       xUnit家族

软件自动化测试的工具有很多种,例如:

       LoadRunner:性能测试、负载测试、压力测试

       QTP:回归测试、测试同一软件的新版本

       Quality Center:基于Web的测试管理工具

       TestDirector:企业级测试管理工具

       Gtestgoogle的开源C++单元测试框架

       xUnit家族:单元测试

其中的xUnit家族是单元测试框架体系,是一种测试思想与模型的集合。它包含了JunitCppUnit Nunit DunitPHPUnitRubyUnit ComUnitHttpUnit等很多语言版本,但是他们的思想是一样的。

xUnit的一般结构有:

        TestFixtures----针对模块的测试代码文件

        TestSuites----组织测试代码的测试套件

        Assertion----断言,用来判断测试的结果

        TestExecution----启动测试的标志

TestResult----测试的结果,详细的测试结果和测试报告

关于测试驱动开发的书籍也有很多,文献[5]是非常经典的一本,它的中译本(文献[6])在国内也是打手欢迎。本文不讨论测试驱动开发,但是测试给开发提供了新的软件开发思路和方法,并且测试驱动开发在部分企业已经开始使用。读者如需了解学习,请参考相关文献,不过,本文列出的文献[5]和文献[6]会是不错的选择哦!

 

4.       NUnit实践

上面说了那么多,现在来个例子吧!

杨辉三角,植物花瓣,黄金比,兔子繁殖 等都涉及到了斐波那契数列,而且这个例子比较简单,那我们就选择斐波那契数列进行实践吧!

声明:本文是用的是NUnit 2.5.9,在本文写作的时候,这个版本是最新的。运行的平台是WindowsXP。如需运行,最好安装Visual Studio 2005,否则会缺运行时库的哦。

3           运行界面

这个函数是比较简单的,按照定义,可以很容易地得到代码,编写函数如下

   int Fib(int n)

        {

            if (n<0)

            {

                return 0;

            }

            if (n == 0)

            {

                return 0;

            }

            if (n==1)

            {

                return 1;

            }

            return Fib(n - 1) + Fib(n - 2);           

 

        }

}

     现在我们进行测试:

1、  f(0)=0,通过。测试效果如右图:

 [Test]

        public void testFib1()

     {

        Assert.AreEqual(0, Fib(0));

    }

2、  f(1)=1,通过。测试效果如右图:

    [Test]

        public void testFib2()

        {

            Assert.AreEqual(1, Fib(1));

     }

3、  n=2,3,4,5,……等等一系列的值,测试之后,都通过了

4、  n的最小值为0,如果是负数呢?根据函数的定义及属性,可以假设f(-1)=0

5、  不管n取值多少,f(n)的最大值是int型变量的最大值。据此,我们需要n的上限值。

6、  如果n的输入值为浮点数,程序会怎样运行呢?

诸如这些遗留问题,都需要单元测试。从我们手里提交的代码,最好必要给别人的工作造成负担,所以单元测试肩负着使代码可靠的重任。

5.       小结

关于单元测试还有很多,包括静态测试、动态测试、调试与评估等。相关的领域还有极限编程(XP),测试驱动开发TDD(说过的),JUnit(它可是NUnit的基础),面向测试的设计(作者刚听说的),Mock对象,驱动模块,桩模块,版本控制CVS等等。这些都有待于实践和感受,在这里干说是用处不大的。

什么时候结束单元测试呢?当软件的单元功能、单元接口与设计需求一致,对于输入能够给出准确的响应,能够容忍一定的错误,能够处理异常,还有,完成单元测试报告。当这些都满足之后,就可以说,本模块完成了。当然,本文也快要结束了。别忘了,高可靠性的模块是组成可靠系统的坚实基础。

 

参考文献

         [1]张海藩.软件工程.北京:人民邮电出版社,2006.1.P6-P8

[2]朱少民.软件测试方法和技术.北京:清华大学出版,2005.7.P37-P38

[3]吕金和. 软件安全性测试研究.计算机安全.2010.8

[4]()托马斯等著,陈伟桩,陶文 .单元测试之道C#:使用NUnit-----程序员修炼三部曲第二部. 电子工业出版社:北京,200501.P7-P12

[5] Kent Beck. Test-Driven Development By Example. Addison Wesley: November 08, 2002

[6]() Kent Beck,孙平平,张小龙,赵辉等译,崔凯校.测试驱动开发(中文版).北京:中国电力出版社.2004

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值