一 单元测试简介
 
单元测试是代码正确性验证的最重要的工具,也是系统测试当中最重要的环节。也是唯一需要编写代码才能进行测试的一种测试方法。在标准的开发过程中,单元测试的代码与实际程序的代码具有同等的重要性。每一个单元测试,都是用来定向测试其所对应的一个单元的数据是否正确。
单元测试是由程序员自己来完成,最终受益的也是程序员自己。可以这么说,程序员有责任编写功能代码,同时也就有责任为自己的代码编写单元测试。执行单元测试,就是为了证明这段代码的行为和我们期望的一致。
单元测试还具有一下几个好处:
 能够协助程序员尽快找到BUG的具体位置
 能够让程序员对自己的程序更有自信
 能够让程序员在提交项目之前就将代码变的更加健壮
 能够协助程序员更好的进行开发
 能够向其他程序员展现你的程序该如何调用
 能够让项目主管更了解系统的当前状况
1.1    能够协助程序员尽快找到BUG的具体位置
在没有单元测试的时代,我们大多数的错误都是通过操作页面的时候发现的。当我们发现一个错误的时候,会根据异常抛出的地点来确定是哪段代码出现了问题。但是大多数时候,我们不会所有方法中都使用Try块去处理异常(这一也是低效的)。因此一旦发现一个异常通常都是最顶层代码抛出的,但是错误往往又是在底层很深层次的某个对象中出现的。当我们找到了这个最初抛出异常的方法的时候,我们可能无法得知这段代码到底是哪里出了问题。只能逐行代码的去查找,一旦这个方法中使用的某个对象在外部有注册事件或者有其他的操作正在与当前方法同步进行,那么就更难发现错误真正的原因了。
有经验的程序员也会知道,大多数的时候,我们并不是真正的在编写新的代码,而是在修改旧的代码出现的错误。通常这个比例会大于2比8,这也是编写代码的时候的二八现象——编写代码的时间是二,而为这段代码找错误、修改错误所花费的时间却是八。
在这种状态之下,我们在找错误的时候会直接编译整个程序,然后通过界面逐步的操作到错误的地方然后再去查找代码中是否有错误。这样的找错误的方法效率非常低。但是当我们拥有单元测试的时候,我们就不需要通过界面去一步一步的操作,而是直接运行这个方法的单元测试,将输入的条件模拟成出现错误的时候输入的信息和调用的方法的形式,这样就可能很快的还原出错误。这样解决起来速度就提高了很多,每次找到错误都去修改单元测试,那么下次就不会再出现相同的错误了。
如果通过模拟,单元测试也没有出现任何异常,这时也可以断定,并非该代码出现的错误,而是其他相关的代码出现的错误。我们只需再调试其他几个相关的代码的单元测试即可找到真正的错误。
1.2    能够让程序员对自己的程序更有自信
很多时候,当主管问我们程序会不会再出问题的时候,我们会很难回答。因为我们没法估计到系统还可能出现什么问题。但是如果这时我们为所有代码都编写了单元测试,而且测试代码的编写是按照标准去写的,这些测试又都能够成功的通过测试。那么我们就完全有自信说出我们的把握有多大。因为在测试代码中,我们已经把所有可能的情况都预料到了,程序代码中也将这些可能预料到的问题都解决了。因此我们会对自己的程序变得越来越自信。
1.3    能够让程序员在提交项目之前就将代买变得更加健壮
大多数程序员在编写代码的时候,都会先考虑最理想化情况下的程序该如何写,写完之后在理想状态下编译成功,然后输入理想的数据发现没有问题。他们就会自我安慰的说“完成了”。然后可能为了赶进度,就又开始作另外的程序了。时间久了这种理想化的程序就越来越多。一旦提交测试,就发现这里有错误那里有错误,然后程序员们再拿出时间来这里补个漏洞那里补个漏洞。而且在补漏洞的过程中,也可能继续沿用这种理想化的思路,就导致了补了这里又导致那里出问题的情况。
但是如果在初期,我们就为每段代码编写单元测试,而且根据一些既定的标准去写,那么单元测试就会提前告诉程序员哪些地方会出现错误。那么他们可能在编写过程中就提前处理了那些非理想状态下的问题。这样我们的代码就会健壮很多。
1.4    能够协助程序员更好的进行开发
“码未动,测试现行。”这是极限编程中倡导的一种编程模式,为什么要这样呢?因为我们在编写单元测试的过程中,其实就是在设计我们的代码将要处理哪些问题。单元测试写的好,就代表你的代码写的好。而且你会根据单元测试的一些预先设想的情况去编写代码,就不会盲目的添加一个属性、添加一个方法了。
1.5    能够向其他程序员展现你的程序该如何调用
通常情况下,单元测试代码中写的都是在各种情况下如何调用那段待测试的代码。因此这个单元测试同时也向其他人员展示了我们的代码该如何调用?在什么情况下会抛出什么异常?等等。这样一个单元测试就变成了一个代码性的帮助文档了。
1.6    能够让项目主管更了解系统当前的状况
传统的管理中,项目的进度、代码的质量都只是通过口头的形式传递到主管那里的。因此有时候主管获得的反馈可能事实。但是如果通过一个完善的单元测试系统,那么主管就可以通过查看单元测试的运行结果和单元测试的代码覆盖率来确定开发人员的工作是否真正完成。
 
 
二 如何编写单元测试
Microsoft Visual Studio 2005中集成了一个专门用来进行测试的组件,该组件能够提供给我们单元测试、压力测试、代码覆盖率等等的测试相关的功能。我们无须借用第三方的测试工具来进行这些测试。
2.1 创建单元测试
该工具可以对任何类、接口、结构等实体中的字段、属性、构造函数、方法等进行单元测试。创建单元测试大致可以分为两类:
 整体测试,整体测试是在类名称上右击鼠标,在下拉菜单中点击创建单元测试选项。这样就可以为整个类创建单元测试了,这时他会为整个类可以被测试的内容全部添加测试方法。开发人员直接在这些自动生成的测试方法中添加单元测试代码就可以了。
 单独测试,如果只想单独对某个方法、属性、字段进行测试,则可以将鼠标焦点放在这个待测试的方法或项目名称之上,然后点击鼠标右键,在右键菜单中选择创建单元测试选项。这样就可以单独为某个方法创建单元测试了。
2.2 编写单元测试代码
创建完单元测试之后,就可以为单元测试编写测试代码了。具体的测试代码的编写标准会在第三章中介绍。
2.3 运行单元测试
单元测试代码编写完毕,就可以通过运行单元测试来进行测试了。需要运行单元测试的时候,需要打开测试管理器窗口。该窗口可以通过菜单中的“测试”-“窗口”——“测试管理器”来打开。打开该窗口之后,就可以在该窗口中看到我们所建立的单元测试的列表。我们可以在列表中勾选某个单元测试前面的复选框。然后右击鼠标在右键菜单中点击“调试选中的测试”或者“运行选中的测试”。
调试选中的测试的时候,我们可以在测试代码中或者我们自己的代码中添加断点并逐步运行以看其状态。
运行选中的测试只会运行测试并不能够进行测试,这时代码的运行是模拟真实软件运行的时候的情况执行的。我们可以根据我们的实际情况来选中执行哪种测试。
2.4 测试结果
运行了测试之后,我们需要查看这次测试的结果。我们可以通过点击菜单中的“测试”——“窗口”——“测试结果”来打开一个测试结果窗口。每次测试都会在测试结果中向我们显示一些记录。我们也可以通过双击这个测试结果,来查看详细的结果信息。
2.5 代码覆盖率
单元测试写的是否合理或者是否达到了要求的一个唯一的标准就是整个测试的代码覆盖率。代码覆盖率其实就是测试代码所运行到的实际程序路径的覆盖率。在实际程序中可能会有很多的循环、判断等分支路径。一个好的单元测试应该能够将所有可能的路径都将走到,这样就可以保证大多数情况都测试过了。
VS2005中也提供了查看代码覆盖率的工具。我们可以通过点击菜单中的“测试”——“窗口”——“代码覆盖率结果”来打开代码覆盖率查看的窗口。
若要进行代码覆盖率的检查,我们必须进行设置,因为系统默认情况下是不进行代码覆盖率检测的。若要打开某个测试的代码覆盖率测试,我们必须点击菜单中的“测试”——“编辑测试运行配置”——“本地测试运行。。。。。。”来打开一个测试配置窗口。在该窗口左侧的列表中选中“代码覆盖率”就会显示代码覆盖率的设置。在这个配置中会显示当前解决方案中可以用来检测代码覆盖率的程序集,我们将需要进行覆盖率检测的程序集选中然后点击“应用”按钮就可以了。
设置完毕之后,我们就可以直接运行单元测试,测试通过后。我们就可以打开代码覆盖率结果窗口,在这里我们就能够看到这些测试覆盖了多少代码。当我们在这里双击某个类的时候,就可以看到VS已经将代码背景改变了颜色。显示为深棕色的代码就是没有覆盖到的代码,我们可以通过在单元测试代码中添加代码来想办法覆盖这些代码。这样一个单元测试的全过程就完成了。
三 单元测试的标准
虽然要进行单元测试的代码会是各种各样的,但是编写单元测试代码还是有规律可循的。测试的对象一般情况下分为方法(包含构造函数)、属性,因此我们按照这两个方向来确定单元测试的标准。
由于现在大多数开发人员还没有真正使用过.NET的单元测试工具,对于单元测试的了解程度也不高。因此我们这里也不便于制定非常多的标准。我们当前主要针对两大方面进行规范:
l 哪些代码需要添加单元测试?
l 单元测试代码的写法?
3.1 哪些代码需要添加单元测试
如果项目正处在一个最后冲刺阶段,主要的编码工作已经基本完成。因此要全面的添加单元测试,其实是比较大的投入。所以单元测试不能一次性的全部加上,我们只能通过一步一步的来进行测试。
第一步,应该对所有程序集中的公开类以及公开类里面的公开方法添加单元测试。
第二步,对于构造函数和公共属性进行单元测试。
第三步,添加全面单元测试。
在产品全面提交之前可以先完成第一步的工作,二三步可以待其他所有功能完成之后再进行添加。由于第二三步的添加工作其实于第一步类似,只是在量上的累加,因此我们先着重讨论第一步的情况。
在作第一步单元测试添加的时候,也需要有选择性的进行,我们要抓住重点进行测试。首先应该针对属于框架技术中的代码添加单元测试。这里就包含操作数据库的组件、操作外部WebService的组件、邮件接收发送组件、后台服务与前提程序之间的消息传递的组件等等。通过为这些主要的可复用代码进行测试,可以大大加强底层操作的正确性和健壮性。
其次为业务逻辑层对界面公开的方法添加单元测试。这样可以让业务逻辑保持正确,并且能够将大部分的业务操作都归纳到单元测试中,保证以后产品发布之后,一旦出现问题可以直接通过业务逻辑的单元测试来找到BUG。
剩下的代码大部分属于代码生成器生成的,而且大多数的操作都是类似的,因此我们可以先针对某一个业务逻辑对象做详细的单元测试。通过这样的规定,单元测试添加的范围就减少了很多。
如果项目是刚刚开始的,那么应当对所有公开的方法和属性都添加单元测试。
3.2 单元测试代码的写法
在编写单元测试代码的时候需要认真的考虑以下几个方面:
l 所测试的方法的代码覆盖率必须达到100%。
l 所测试的代码内部的状态,例如执行了某个方法之后,该方法所在的类中某个属性或者返回值是否与预期相同。
l 被测试代码所使用的外部设备的状态,如数据库是否可读、网络是否可用、打印机是否可用、WebService是否可用等等。
每一段单元测试代码,必须考虑到以上的三个问题,并且对于这些问题都要有相应的测试。
3.2.1  代码覆盖率要求
在2.5小节中已经讲了什么是代码覆盖率和代码覆盖率查看的方法。在这里我们着重来讲怎样将代码覆盖率提升到100%。
一般情况下,代码覆盖率低,说明测试代码中没有过多的考虑某些特殊情况。特殊情况包括:
l 边界条件数据,比如值类型数据的最大值、最小值、DBNull,或者是方法中所使用的条件边界,例如a>100那么100就变成了这个数据的边界。而且在测试的时候还必须把超出边界的数据作为测试条件进行测试。
l 空数据,一般空数据对应于引用类型的数据,也就是Null值。
l 格式不正确数据,对于引用类型的数据或者结构对象,类型虽然正确但是其内部的数据结构不正确的数据。例如一个数据库实体对象,数据库中要求其某个属性必须为非空,但是这时我们可以属于一个空。这样这个对象就属于一个不正确数据库。
这三种数据都是针对被测试方法中所使用的外部数据来说的。方法中使用的外部数据无非就是方法参数传入的数据和方法所在的对象的属性或者字段的数据。因此在编写测试代码的时候就必须将这些使用到的数据设置为上面这几种情况的数据来检测方法执行的情况。这才能保证方法编写是正确的。
在编写单元测试代码的时候先了解到被测试方法可能会使用的外部数据,然后将这些外部数据一次设置为上面规定的这几种情况,然后再执行方法。这样就基本可以达到外部数据所有情况都能够正确测试到了。
通过这种方法编写的单元测试代码覆盖率一般可以超过80%。
 
3.2.2 预期值是否达到
在编写单元测试的时候,不能单纯的追求代码覆盖率。有时候代码覆盖率已经达到了100%,程序也能正常运行,但是可能会出现方法执行完毕之后某些数据并非预期的数值。这时就必须对执行的结果进行断言。在.NET提供的单元测试模块中,可以在单元测试中直接使用一个类的一些静态方法来判断某个值是否达到了预期的情况。这个类是Assert。在这个类中公开了很多判断等效性、判断开关性、判断非空性等一系列方法。这些方法可以让你提前做出预测,一旦程序执行之后,如果这些断言不能通过,就代表代码有错误。
在使用断言的时候,我们要求要达到平均5行测试代码就要有一个断言。
通过添加断言,我们就可以对程序执行过程中数据的正确性做一个检测,保证我们的程序不出现写错数据的情况或者出现错误状态的情况。
3.2.3 外部设备状态更改时测试是否正常通过
当代码覆盖率和预期值都达到了我们的要求之后,整个程序其实就基本达到了质量标准。但是这样还不全面,因为很多程序都要使用到外部的设备或者程序,例如数据库、打印机、网络、串行口、并行口等等。当这些设备发生改变或者不可用的时候,程序就可能出现一些不可预知的错误。因此一个健壮的程序也必须考虑到这些情况,这时通常都是通过将这些设备确定的设置为这些不正常状态来检测程序可能会出现的问题。然后再在测试程序中将这些条件加上。
 
上面所介绍的只是简单的单元测试的入门级别的要求,当然真正的单元测试还有很多更加复杂的要求和测试技巧。但是对于一个初学者而言,如果能达到上述的要求,那么你的代码的健壮性应该能够满足大部分要求了。只是在比较标准的工业化开发的时候,才需要将单元测试继续深化。如果有时间的话,我会在以后再详细阐述较深层次的单元测试方法。

出处:
http://blog.csdn.net/lovenina/article/details/2291568
http://blog.csdn.net/lovenina/article/details/2305376

Visual Studio 2005 自带单元测试的更多相关文章

  1. Visual Studio 2012使用NUnit单元测试实践01,安装NUnit并使用

    在Visual Studio 2012中,默认使用Microsoft自带的MS-Test测试框架.但,Visual Studio同样允许使用第三方测试框架,比如NUnit,xUnit,MbUnit,等 ...

  2. Using Nuget in Visual Studio 2005 & 2008

    NuGet is a Visual Studio extension that makes it easy to install and update third-party libraries an ...

  3. Visual Studio 2005 搭建Windows CE 6.0环境之准备

    Microsoft Visual Studio 2005 Visual Studio 2005 Professional 官方90天试用版英文版:http://download.microsoft.c ...

  4. Visual Studio 2005安装qt-win-commercial-src-4.3.1,并设置环境变量

    虽然已经在Visual Studio 2005下安装Qt4已经n次了,还是打算在上写写安装方法. qt-win-commercial-src-4.3.1.zip.qt-vs-integration-1 ...

  5. Visual Studio 2005 移植 - WINVER,warning C4996, error LINK1104

    Visual Studio 2005 移植 - WINVER,warning C4996, error LINK1104 一.WINVER  Compile result:  WINVER not d ...

  6. visual studio 2005提示脚本错误 /VC/VCWizards/2052/Common.js

    今天在做OCX添加接口的时候,莫名其妙的遇到visual studio 2005提示脚本错误,/VC/VCWizards/2052/Common.js. 网上找了很多资料,多数介绍修改注册表“vs20 ...

  7. visual studio 2005 win7 64位版下载

    http://www.121down.com/soft/softview-19659.html 软件标签: visual studio visual studio 2005是由微软推出的一款基于.ne ...

  8. win7兼容visual studio 2005 的方法

    http://blog.sina.com.cn/s/blog_74d572890100xv7p.html 今天花了4个小时,结合网上的介绍,本人终于找到了一个可以在win7环境下运行visual st ...

  9. visual studio 2010 自带reporting报表本地加载的使用

    原文:visual studio 2010 自带reporting报表本地加载的使用 在这家公司时间不长,接触都是之前没玩过的东东,先是工作流引擎和各种邮件短信的审核信息,后又是部署reporting ...

随机推荐

  1. 尚未指定报表“Report1”的报表定义

    在做RDLC项目中遇到这样的错误 本地报表处理期间出错. 尚未指定报表“Report1”的报表定义 未将对象引用设置到对象的实例. 解决方案: 打开reportViewer->LocalRepo ...

  2. Python: 使用生成器创建新的迭代模式

    使用一个生成器函数来定义一个函数模式. def frange(start, stop, increment): x = start while x < stop: yield x x += in ...

  3. javascript数组总结

    数组是一个有序的集合,javascript数组中的元素的类型可以是任意的,同一个数组不同元素之间的类型也是可以不同的.数组也是对象,有个length属性,记录数组的长度. 创建数组有两种方法: 数组直 ...

  4. 几种Memcache的状态监控的工具,以及安装和使用【linux系统】

    1.Memcache-top的简介及安装和用法 简介:memcache-top是用perl语言编写的,可以运行在term下.它能够像top一样显示各个memcached节点的状态变化,其中包括系统管理 ...

  5. sqoop2-1.99.5-cdh5.5.4.tar.gz的部署搭建

    不多说,直接上干货! 首先,说下博主我,为什么,好端端的Sqoop1用的好好的,然后又安装和学习Sqoop2? 因为,在Cloudera Hue里的Sqoop,是需要Sqoop2. HUE配置文件hu ...

  6. 前端学习笔记之css清除浮动float的七种常用方法总结和兼容性处理

    在清除浮动前我们要了解两个重要的定义: 浮动的定义:使元素脱离文档流,按照指定方向发生移动,遇到父级边界或者相邻的浮动元素停了下来. 高度塌陷:浮动元素父元素高度自适应(父元素不写高度时,子元素写了浮 ...

  7. bzoj1611 / P2895 [USACO08FEB]流星雨Meteor Shower

    P2895 [USACO08FEB]流星雨Meteor Shower 给每个点标记一下能够走的最迟时间,蓝后bfs处理一下 #include<iostream> #include<c ...

  8. Spark 任务提交脚本

    说明 该脚本是根据输入起始日期-结束日期,执行从数据库拉取日期间隔数据到HDFS.日期间隔中的日期就是每一年的自然日. 日期格式可以是以下几种:2018-01-01 2018-12-31 [-][/] ...

  9. The current .NET SDK does not support targeting .NET Core 3.0

    编译错误 Severity Code Description Project File Line Suppression StateError NETSDK1045 The current .NET ...

  10. 实时刷新winform中的某一个控件上的文字

    需要注意的是,必须从UI线程,另外启动一个线程才可以. 在新线程调用异步刷新就OK了 Thread thread; private void button1_Click(object sender, ...