可不可不要这么样徘徊在目光内 / 你会察觉到我根本寂寞难耐 / 即使千多百个深夜曾在梦境内 / 我有吻过你这毕竟并没存在 / 人声车声开始消和逝 / 无声挣扎有个情感奴隶 / 是我多么的想她 / 但我偏偏只得无尽叹谓 / 其实每次见你我也着迷 / 无奈你我各有角色范围 / 就算在寂寞梦内超出好友关系 / 唯在暗里爱你暗里着迷 / 无谓要你惹上各种问题 / 共我道别吧别让空虚使我越轨 /

发布新日志

  • 性能测试指标的基本概念(转)

    2007-08-24 15:52:29

     

    性能测试指标的基本概念


    吞吐量/处理能力
    处理能力又叫吞吐量,指的是单位时间内处理的客户端请求数量。通常情况下,吞吐量用请求数/ Or 页面数/秒来衡量。从业务角度看,吞吐量也可以用访问人数/Or页面访问量/天来衡量。

    负载
    负载分为客户端负载和服务器端负载客户端负载的通俗解释就是有多少个用户在同时使用软件服务器端负载的通俗解释就是有多少个请求同时到达了服务器端,要求服务器进行处理。例如,某个网站当前有10000个人在线访问,从他们的客户端层面看过去,这个负载就是客户端负载,为10000。若某个网站当前有10000个人在线访问,某一时刻,从他们的客户端同时发出了1000个页面的请求到服务器,从服务器端层面看过去,这个负载就是服务器端负载,为1000

    响应时间
    响应时间是可以判断一个被测应用系统是否存在性能瓶颈的最直观的要素。例如,在执行完性能测试后,发现某个交易的“平均响应时间”为8秒,超过了预先确定下来的性能指标“该交易的性能指标为平均响应时间要小于等于3秒”。此时,就可以认为被测应用系统存在性能瓶颈了,要利用一定的手段去探查被测应用系统中哪个地方引起了系统的处理效率低以及低的原因了。响应时间一般包括最大响应时间和平均响应时间,响应时间包括网络上的传输时间,WEB服务器上处理时间、APP服务器上的处理时间、DB服务器上的处理时间,响应时间不包括浏览器上的内容显示时间。

    同时在线用户
    对于一个网站来讲,当一个用户登录到该网站的首页后,开始在该网站上进行各种操作,包括浏览网页、检索内容、提交表单等,这个过程中的用户称为在线用户。若同一时间点或同一个时间段内,有很多这样的用户在访问该网站,这些用户统称为该网站的同时在线用户。同时在线用户的另一层理解是,将应用系统整体看作是一个黑盒子,从用户的客户端层面看向系统,总共有多少个人在使用它。当进行性能测试时,如果你使用的是同时在线用户,则可以称之为同时在线负载。

    超级并发用户
    对于一个网站来讲,可能存在WEB服务器、应用服务器、数据库服务器三个层次,而用户所使用的浏览器是在最外面的客户端层面。如果某个时间点或时间段内,共有1000个用户同时在线,他们进行着各种各样的操作,而某个时间点上可能存在10个左右的用户同时进行了一个或多个操作,导致WEB服务器同时接收到了10个左右的交易请求,我们称这个10个左右的用户为超级并发用户。当进行性能测试时,如果你使用的是超级并发用户,则可以称之为超级并发负载。

    性能测试脚本
    脚本是用负载模拟工具开发出来的。脚本是一些代码的组合体,它用代码来实现用户对应用系统的操作。例如,你在一个网站上访问首页、输入用户名和密码后点击登录按钮进行登录,这是用户对应用系统的两步操作内容,在脚本中则包含了实现这两个操作步骤的代码。如果你要模拟10000个用户的负载,这10000个用户中50%进行首页的访问、20%进行注册、20%进行查询、10%进行某个页面的浏览,则你需要制作5个脚本,分别是首页访问脚本、注册脚本、查询脚本、页面浏览脚本。

    事务
    事务是脚本的一个特性,每个事务都包含开始事务和结束事务。事务用来衡量脚本中一行代码或多行代码的执行所耗费的时间。你可以将开始事务放置在脚本中某行代码的前面,将结束事务放置在该行代码的后面,在该脚本的虚拟用户运行时,这个事务将衡量该行代码的执行花费了多长时间。

    交易
    交易分为业务层面和技术层面两种定义。业务层面交易是指完成一次完整的业务操作,例如进行一次取款、查询操作。技术层面的交易是指进行一次应用程序至应用程序、或者应用程序至数据库的系统操作。一般的一笔业务交易由多笔技术交易组成,根据业务交易的复杂度和系统应用架构的不同,其比例大致为12-110

    TPS
    HPS
    TPS (Transactions Per Second)
    是估算应用系统性能的重要依据。其意义是应用系统每秒钟处理完成的交易数量,尤其是交易类系统。一般的,评价系统性能均以每秒钟完成的技术交易的数量来衡量。系统整体处理能力取决于处理能力最低模块的TPS值。依据经验,应用系统的处理能力一般要求在10-100左右。不同应用系统的TPS有着十分大的差别,一般需要通过性能测试进行准确估算。当系统没有达到性能瓶颈时,TPS随着负载的增加呈近似线性增长,当接近性能瓶颈时出现拐点;如果系统健壮性较好,在到达性能瓶颈后,TPS基本保持水平,不会再随着负载的增加而有显著增长;而如果系统存在比较严重的性能问题,当到达性能瓶颈后,TPS会出现明显的下降趋势。HPS(Hits per Second)每秒点击次数,是指在一秒钟的时间内用户对Web页面的链接、提交按钮等点击总和它一般和TPS成正比关系,是B/S系统中非常重要的性能指标之一。
    TPS
    可以有多种衡量单位,在进行性能测试的业务模型分析时使用,例如:
    1)在税务系统中,可以用“系统每个月要处理10万用户的业务操作”,这里的TPS用企业数/月来衡量;(2)在税务系统中,也可以用“系统在第七天的8个小时内要处理4万用户的业务操作”,这里的TPS用企业数/天来衡量;(3)在税务系统中,也可以用“系统在第七天的10点到11点之间要处理1.2万用户的3种缴税交易操作,即3.6万次缴税交易操作”,这里的TPS用交易数/小时来衡量;(4)在税务系统中,也可以用“系统在第七天的10点到11点之间要处理1.2万用户的3种缴税交易操作,即3.6万次缴税交易操作,每次缴税交易要从客户端向服务器发送平均10HTTP请求,即36万次HTTP请求操作”,这里的TPS用请求数/小时来衡量。
    HPS
    是用来衡量很多用户使用客户端进行操作,向服务器发送请求的效率。我们认为HPS表现的是最终用户的整体行为,是衡量在线负载程度的一个指标。而TPS表现的是服务器端的程序行为,是衡量服务器处理能力高低的一个主要指标。
    例如:HPS=“点击次数/秒”;TPS=“处理事务数/秒”,HPSTPS没有绝对的关系。

    性能测试实现的准确性
    在进行了正确的性能测试分析后,获得了正确的性能测试需求,从而使用性能测试工具开发相应的性能测试脚本、开发相应的性能测试场景、在性能测试脚本中利用性能测试数据、在性能测试脚本中设置相应的思考时间、在性能测试场景中设置运行的参数等,以期能利用自动化的性能测试工具模拟现实中大量用户同时访问被测系统的情形。即,如果性能测试工具操作不当,将会导致无法准确的实现“模拟实际情况”的目标。例如,某些性能测试工程师在使用性能测试工具时不懂得利用“检查点”这个功能,从而无法发现在性能测试执行过程中大量虚拟用户甚至没有登陆到系统中的严重问题,仍然认为性能测试执行效果良好,被测系统性能没有问题。

    Web
    服务器和APP服务器
    通俗的讲,Web服务器传送(serves)页面使浏览器可以浏览,然而应用程序服务器提供的是客户端应用程序可以调用(call)的方法(methods)。确切一点,你可以说:Web服务器专门处理HTTP请求(request),但是应用程序服务器是通过很多协议来为应用程序提供(serves)商业逻辑(business logic)Web服务器(Web Server)Web服务器可以解析(handles)HTTP协议。当Web服务器接收到一个HTTP请求(request),会返回一个HTTP响应(response),例如送回一个HTML页面。为了处理一个请求(request)Web服务器可以响应(response)一个静态页面或图片,进行页面跳转(redirect),或者把动态响应(dynamic response)的产生委托(delegate)给一些其它的程序例如CGI脚本,JSP(JavaServer Pages)脚本,servletsASP(Active Server Pages)脚本,服务器端(server-side)Javascrīpt,或者一些其它的服务器端(server-side)技术。无论它们(译者注:脚本)的目的如何,这些服务器端(server-side)的程序通常产生一个HTML的响应(response)来让浏览器可以浏览。要知道,Web服务器的代理模型(delegation model)非常简单。当一个请求(request)被送到Web服务器里来时,它只单纯的把请求(request)传递给可以很好的处理请求(request)的程序(译者注:服务器端脚本)Web服务器仅仅提供一个可以执行服务器端(server-side)程序和返回(程序所产生的)响应(response)的环境,而不会超出职能范围。服务器端(server-side)程序通常具有事务处理(transaction processing),数据库连接(database connectivity)和消息(messaging)等功能。虽然Web服务器不支持事务处理或数据库连接池,但它可以配置(employ)各种策略(strategies)来实现容错性(fault tolerance)和可扩展性(scalability),例如负载平衡(load balancing),缓冲(caching)。集群特征(clusteringfeatures)经常被误认为仅仅是应用程序服务器专有的特征。
    应用程序服务器(The Application Server)根据我们的定义,作为应用程序服务器,它通过各种协议,可以包括HTTP,把商业逻辑暴露给(expose)客户端应用程序。Web服务器主要是处理向浏览器发送HTML以供浏览,而应用程序服务器提供访问商业逻辑的途径以供客户端应用程序使用。应用程序使用此商业逻辑就象你调用对象的一个方法(或过程语言中的一个函数)一样。应用程序服务器的客户端(包含有图形用户界面(GUI))可能会运行在一台PC、一个Web服务器或者甚至是其它的应用程序服务器上。在应用程序服务器与其客户端之间来回穿梭(traveling)的信息不仅仅局限于简单的显示标记。相反,这种信息就是程序逻辑(program logic)。 正是由于这种逻辑取得了(takes)数据和方法调用(calls)的形式而不是静态HTML,所以客户端才可以随心所欲的使用这种被暴露的商业逻辑。在大多数情形下,应用程序服务器是通过组件(component)的应用程序接口(API)把商业逻辑暴露(expose)(给客户端应用程序)的,例如基于J2EE(Java 2 Platform, Enterprise Edition)应用程序服务器的EJB(Enterprise JavaBean)组件模型。此外,应用程序服务器可以管理自己的资源,例如看大门的工作(gate-keeping duties)包括安全(security),事务处理(transaction processing),资源池(resource pooling), 和消息(messaging)。就象Web服务器一样,应用程序服务器配置了多种可扩展(scalability)和容错(fault tolerance)技术。 例如,设想一个在线商店(网站)提供实时定价(real-time pricing)和有效性(availability)信息。这个站点(site)很可能会提供一个表单(form)让你来选择产品。当你提交查询(query)后,网站会进行查找(lookup)并把结果内嵌在HTML页面中返回。网站可以有很多种方式来实现这种功能。我要介绍一个不使用应用程序服务器的情景和一个使用应用程序服务器的情景。观察一下这两中情景的不同会有助于你了解应用程序服务器的功能。
    情景1:不带应用程序服务器的Web服务器在此种情景下,一个Web服务器独立提供在线商店的功能。Web服务器获得你的请求(request),然后发送给服务器端(server-side)可以处理请求(request)的程序。此程序从数据库或文本文件(flat file,译者注:flat file是指没有特殊格式的非二进制的文件,如propertiesXML文件等)中查找定价信息。一旦找到,服务器端(server-side)程序把结果信息表示成(formulate)HTML形式,最后Web服务器把会它发送到你的Web浏览器。简而言之,Web服务器只是简单的通过响应(response)HTML页面来处理HTTP请求(request)
    情景2:带应用程序服务器的Web服务器情景2和情景1相同的是Web服务器还是把响应(response)的产生委托(delegates)给脚本(译者注:服务器端(server-side)程序)。然而,你可以把查找定价的商业逻辑(business logic)放到应用程序服务器上。由于这种变化,此脚本只是简单的调用应用程序服务器的查找服务(lookup service),而不是已经知道如何查找数据然后表示为(formulate)一个响应(response)。 这时当该脚本程序产生HTML响应(response)时就可以使用该服务的返回结果了。在此情景中,应用程序服务器提供(serves)了用于查询产品的定价信息的商业逻辑。(服务器的)这种功能(functionality)没有指出有关显示和客户端如何使用此信息的细节,相反客户端和应用程序服务器只是来回传送数据。当有客户端调用应用程序服务器的查找服务(lookup service)时,此服务只是简单的查找并返回结果给客户端。通过从响应产生(response-generating)HTML的代码中分离出来,在应用程序之中该定价(查找)逻辑的可重用性更强了。其他的客户端,例如收款机,也可以调用同样的服务(service)来作为一个店员给客户结帐。相反,在情景1中的定价查找服务是不可重用的因为信息内嵌在HTML页中了。总而言之,在情景2的模型中,在Web服务器通过回应HTML页面来处理HTTP请求(request),而应用程序服务器则是通过处理定价和有效性(availability)请求(request)来提供应用程序逻辑的。
    警告(Caveats) 现在,XML Web Services已经使应用程序服务器和Web服务器的界线混淆了。通过传送一个XML有效载荷(payload)给服务器,Web服务器现在可以处理数据和响应(response)的能力与以前的应用程序服务器同样多了。另外,现在大多数应用程序服务器也包含了Web服务器,这就意味着可以把Web服务器当作是应用程序服务器的一个子集(subset)。虽然应用程序服务器包含了Web服务器的功能,但是开发者很少把应用程序服务器部署(deploy)成这种功能(capacity)(译者注:这种功能是指既有应用程序服务器的功能又有Web服务器的功能)。相反,如果需要,他们通常会把Web服务器独立配置,和应用程序服务器一前一后。这种功能的分离有助于提高性能(简单的Web请求(request)就不会影响应用程序服务器了),分开配置(专门的Web服务器,集群(clustering)等等),而且给最佳产品的选取留有余地。

    性能瓶颈
    性能瓶颈实际上就是一个软件的性能缺陷,最通俗的理解“性能瓶颈”。
    1)硬件上的性能瓶颈主要指的是CPURAM方面的问题。例如,在进行软件需求分析、概要设计时,确定了在数据库服务器上需要6CPU12G内存,但是在测试时,发现CPU的持续利用率超过95%,这时可以认为在硬件上出现了性能瓶颈。
    2)应用软件上的性能瓶颈一般指的是应用服务器、WEB服务器等应用软件,还包括数据库系统。例如,在WEBLogic平台上配置了JDBC连接池的参数,最大连接数为50,最小连接数为5,增加量为10。在测试时发现,当负载增加时,现有的连接数不足,系统会动态生成10个新的连接数,这样导致了交易处理的响应时间大大的增加。这时可以认为在应用软件上出现了性能瓶颈。
    3)应用程序上的性能瓶颈,一般指的是开发人员新开发出来的应用程序。例如,用Java或者C开发出来的部署在应用服务器上用于用户交易请求处理的应用程序。例如,某个开发员开发了一个缴费处理程序,在测试时发现,这个缴费处理程序在处理用户发过来的并发缴费请求时,只能串行处理,无法并行处理,导致缴费交易的处理响应时间非常长,这时可以认为在应用程序上出现了性能瓶颈。
    4)操作系统上的性能瓶颈,一般指的是WindowsUnixLinux这些操作系统。例如,在windows系统中,虚拟内存设置的不合理,都指定为C驱提供虚拟内存,在测试时发现当出现物理内存不足时,虚拟内存的交换效果非常不理想,导致交易的响应时间大大增加。这时可以认为在操作系统上出现了性能瓶颈。
    5)网络设备上的性能瓶颈,一般指的是防火墙、动态负载均衡器、交换机等设备。例如,在动态负载均衡器上设置了动态分发负载的机制,当发现某个应用服务器上的硬件资源已经到达极限时,动态负载均衡器将后续的交易请求发送到其它负载较轻的应用服务器上。在测试时发现,动态负载均衡机制没有起到相应的作用,这时可以认为在网络设备上出现了性能瓶颈。

     

  • 单元测试工具Numega

    2007-08-23 22:27:54

    1 前言

    我在本文中详细介绍了测试工具NuMega Devpartner(以下简称NuMega)的使用方法。

    NuMega是一个动态测试工具,主要应用于白盒测试。该工具的特点是学习简单、使用方便、功能有效。NuMega共有三个独立的子功能——BoundsCheckerTrueCoverage、TrueTimeBoundsChecker为代码检错工具,TrueCoverage为测试覆盖率统计工具,TrueTime为程序运行性能测试工具

    本文挡通过三章对NuMega三个子功能的使用方法进行了介绍,各部分之间内容独立。如果你想了解NuMega的各项功能,建议阅读本文挡全部内容,如果你只想了解NuMega提供的某一个子功能的相关信息,按目录查看相应的章节即可。

    需要说明的一点是,本文挡中所介绍的测试工具NuMega,专指NuMega for Visual C++版,对于NuMega for Visual Basic版和NuMega for Delphi版的使用说明,不在本文挡的介绍范围之内,这一点请注意。

    2安装

    NuMega的安装很简单。获得NuMega安装程序后,点击setup.exe进行安装即可。在安装过程中不需要什么特殊的设置。

    不过有一点需要说明,在安装NuMega之前,应该确保你的机器上已经安装好了Visual C++,因为只有这样才能使NuMega成功的集成到Visual C++开发环境中去。

    好了,下面我们分三个部分,分别介绍BoundsChecker、TrueCoverage、TrueTime的使用方法。

    3 BoundsChecker

    BoundsChecker 是一个Run-Time错误检测工具,它主要定位程序在运行时期发生的各种错误。BoundsChecker能检测的错误包括:

    1))1、指针操作和内存、资源泄露错误,比如:

    内存泄露;

    资源泄露;

    对指针变量的错误操作。

    22、内存操作方面的错误,比如:

      内存读、写溢出;

      使用未初始化的内存。

    33、API函数使用错误

    BoundsChecker安装成功后,在你的VC++集成开发环境中,会多出了一个名为BoundsChecker的菜单,如下所示:

    1.jpg

    3-1 BoundsChecker在VC++集成开发环境中添加的菜单

    BoundsChecker 已经非常完好的集成到VC++集成开发环境中了。

    使用BoundsChecker对程序的运行时错误进行检测,有两种使用模式可供选择。一种模式叫做ActiveCheck,一种模式叫做FinalCheck。下面分别进行介绍。

    3.1 ActiveCheck

    ActiveCheck是BoundsChecker提供的一种方便、快捷的错误检测模式,它能检测的错误种类有限,只包括:内存泄露错误、资源泄露错误、API函数使用错误。

    要想使用ActiveCheck模式来检测程序的运行时错误,只需在VC++集成开发环境中打开BoundsChecker功能,然后从调试状态运行程序即可。此时ActiveCheck会在后台自动运行,随时检测程序是否发生了错误。下面说一下具体的使用步骤。

    3.1.1 用ActiveCheck来检测错误

    使用ActiveCheck的具体的操作步骤如下:

    首先,在VC++集成开发环境中打开你要对其进行测试的程序,同时保证项目处于Debug编译状态下。

    其次,确保VC++集成开发环境中[BoundsChecker/Integrated Debugging]菜单项和[BoundsChecker/Report Errors and Events]菜单项处于被选中的状态。只有这两项被选中,BoundsChecker才会在程序运行过程中发挥作用。

    最后,在VC++集成开发环境中选择[Build/ Start Debug/Go]菜单命令,在Debug状态下运行程序,ActiveCheck也在后台开始运行了。

    这时,就可以按照制定好的测试用例,对程序进行操作。凡是程序执行过的代码,如果存在错误,ActiveCheck就会记录下来。

    有一个地方要说一下,在[BoundsChecker]菜单中有一项[Report Errors Immediately],如下图所示:

    2.jpg

    3-2 关于[BoundsChecker / Report Errors Immediately] 菜单项

    该菜单项对于ActiveCheck 模式,以及下面就要介绍的FinalCheck模式的作用是一样的,即:如果不选中该项,则BoundsChecker会记录程序运行过程中发现的各种错误,直到程序结束后再进行报告;当选中该菜单项时,在程序的运行过程中,一旦BoundsChecker发现错误,会马上弹出如下的对话框进行提示:

    3.jpg

    3-3 错误报告对话框

    下面按图中标注的数字序号解释一下对话框中各个按钮的功能:

    按钮1:点击该按钮,则表示先暂时不理会这个错误,继续执行程序。

    按钮2:点击该按钮,则会马上跳转到出现问题的代码行处。处理完问题后,点击[Build/ Start Debug/Go]菜单项,可以继续执行程序,进行检测。

    按钮3:点击该按钮,则将该错误添加到被忽略的错误列表中去,当再次出现这个问题时,BoundsChecker将不会进行报告。

    按钮4:点击该按钮,则立即终止程序的执行。

    按钮5:点击该按钮,会显示当前内存的申请、使用情况。

    按钮6:点击该按钮,会得到当前这个错误的帮助信息。

    按钮7、8: 这两个按钮与[BoundsChecker\Report Errors Immediately]和[BoundsChecker\ Report Errors and Event] 菜单命令的功能是完全一样的,在此不再赘述。

    按钮9:点击该按钮,会显示/隐藏与该错误有关的函数调用堆栈情况,以及具体的出错代码行的位置。

    是否选中[BoundsChecker/Report Errors Immediately]菜单项,完全取决于你自己的喜好,以及测试时的具体情况。如果你想要BoundsChecker在程序运行过程中实时向你汇报发现的错误,那么你就选中这个菜单项;如果想等到操作结束后,再对操作过程中BoundsChecker发现的错误统一进行分析,就不必选中这个菜单项。我在平常使用过程中更偏向于使用后一种。

    3.1.2 分析错误

    在你操作全部结束,退出程序后,

    BoundsChecker 会显示一个所发现错误的列表。我们需要对列表中罗列的错误进行分析,来确定错误的原因和位置。

    在错误检测结果列表中,罗列出了在程序的执行过程中ActiveCheck检测到的所有的内存泄露、资源泄露和API函数使用错误的相关信息。如下图所示:

    4.jpg

    3-4 错误检测结果

    在左边的窗口中,逐条列出了程序在内存、资源、API 函数使用上的问题,包括:该问题的种类,该问题发生的次数,如果是内存泄露,损失了多少内存,以及发生该问题的代码位置等等。当你用鼠标单击选中某一条记录时,在右边的窗口中会显示出与该条错误记录相对应的函数调用堆栈情况。当你用鼠标双击某一条错误记录时,会定位到引发该错误的源代码处。

       

    好了,BoundsChecker在ActiveCheck模式下的使用方法至此介绍完了,是不是很简单?

    ActiveCheck模式下检测程序时,程序的运行速度基本不受影响,但其缺点是检测的错误种类有限,即只能检查出内存泄露错误、资源泄露错误、API函数使用错误。BoundsChecker 提供了另外一种检测错误的模式—— FinalCheck,也就是我们在前面提到的BoundsChecker的第二种使用模式。 FinalCheck可以检测出程序中更多的错误。下面我们就对它进行介绍。

    3.2 用 FinalCheck检测更多的错误

    FinalCheck具有BoundsChecker提供的所有检错功能。FinalCheck 是ActiveCheck的超集,它除了能够检测出ActiveCheck能够检测出的错误,还能发现很多 ActiveCheck 不能检测到的错误,包括:指针操作错误、内存操作溢出、使用未初始化的内存等等,并且,对于ActiveCheck能检测出的错误,FinalCheck能够给出关于错误更详细的信息。所以,我们可以把FinalCheck认为是ActiveCheck的功能增强版。我们付出的代价是:程序的运行速度会变慢,有时甚至会变的很慢。

    要想在FinalCheck 模式下测试程序,不能使用VC++集成开发环境提供的编译连接器来构造程序,而必须要使用BoundsChecker提供的编译连接器来编译连接程序。当 BoundsChecker的编译连接器编译连接程序时,会向程序中插装一些错误检测代码,这也就是FinalCheck能够比ActiveCheck找到更多错误的原因。

    下面就

    介绍一下如何在FinalCheck模式下对程序进行测试:

    1在VC++集成开发环境中打开你所要测试的项目。

    2由于要使用BoundsChecker的编译连接器重新编译连接程序,所以我们为BoundsChecker独自构造一个文件夹。在VC++集成开发环境中,具体操作方法是:

    A)点击[ Build/Configurations...]菜单命令。

    B)在弹出的对话框中点击 Add 按钮。在Configuration 编辑框中添入你为BoundsChecker创建的文件夹的名称,这个名称是任意的,比如我们取名为BoundChecker。

    C)在 Copy settings from组合框中选中 XXX—Win32 Debug项,然后点击OK按钮,接着点击Close按钮。

    现在,我们已经为FinalCheck构造好了一个文件夹。

    3 点击[Build/Set Active Configuration…] 菜单命令,选中你刚才为BoundsChecker建的文件夹, 然后点击OK按钮。这样BoundsChecker编译连接程序时生成的中间文件、可执行程序,都会被放到该文件夹下。

    4选择[BoundsChecker/Rebuild All with BoundsChecker] 菜单命令,对程序重新进行编译连接,也就是在这时,BoundsChecker向被测程序的代码中加入了错误检测码。编译连接完成后,BoundsChecker会在你为BoundsChecker构造的文件夹中生成可执行文件。

    FinalCheck模式下对程序进行检测的准备工作都已经做好,这时可以启动程序开始测试了,

    操作步骤与在ActiveChecker模式下没什么区别。具体步骤如下:

    1. 确保VC++集成开发环境中[BoundsChecker/ Integrated Debugging]菜单项和[BoundsChecker/Report Errors and Events]菜单项处于选中状态。
    2. 点击[ Build\Start Debug]菜单,选中“Go” 菜单项。程序开始在Debug状态下运行。
    3. 按照你制定好的测试用例,对程序进行操作。 
    4. BoundsChecker检测到了错误时,会弹出窗口向你汇报,你可以当时就进行处理,也可以等到你的操作全部完成,退出程序之后再对列出的这些错误进行分析。这完全取决于你是否选中了[BoundsChecker/Report Errors Immediately] 菜单项。
    5. 退出程序后,BoundsChecker会给出错误检测结果列表。该错误列表与ActiveChecker给出的错误列表的查看方法完全一样。只不过这个列表中所报告的信息会更多、更详细一些。 

    好了,BoundsChecker在FinalCheck模式下的使用也介绍完了。ActiveChecker、FinalCheck这两种模式,比较而言各有长短。ActiveChecker使用方便,只需在Debug状态下直接运行程序即可,并且程序的运行速度较快,但检测的错误种类有限;FinalCheck模式下,需要使用BoundsChecker的编译连接器重新编译连接生成可执行程序,并且程序的运行速度比较慢,但检测的错误种类、提供的错误相关信息要多于ActiveChecker。所以,何时使用何种模式,应根据当时的具体情况而定。

    3.3 检测Win32 API函数的兼容性

    BoundsChecker还提供了一个功能——检测程序中使用的Win32 API函数在不同平台上的兼容性。该功能与前面提到的ActiveChecker、FinalCheck模式没有什么关系,它是独立的一个功能。

    虽然大多数Win32 API函数都适用于Win95、Win98、Win2000、WinNT等不同的Windows操作系统平台,但并不是所有的API函数都满足这种情况。你可能不知不觉的使用了在某一个平台下允许,在另一个平台下却不允许使用的API函数,而项目的要求是:程序能够在这两种平台下运行。 BoundsChecker提供的这个检测Win32 API函数兼容性的功能,恰好能够处理这个问题。

    该功能的使用方法如下:

    启动[BoundsChecker/View/Compliance Report]菜单命令,如下图所示:

    5.jpg

    3-5 启动Win32 API函数兼容性检测功能

    会弹出下面的窗口:

    6.jpg

    3-6Win32 API函数兼容性检测功能

    在对话框中选择程序承诺能够运行的平台,以及被要求遵从的其他标准(标准C和扩展的标准C),点击“OK”按钮,BoundChecker会给出兼容性检测报告。

    3.4 忽略错误

    在某些情况下,我们需要忽略BoundsChecker报告的一些错误,这些情况包括:

    1 误报。BoundsChecker 指定程序中的某段代码存在错误,但经过我们的仔细检查,证实程序确实没有这个错误,这是BoundsChecker的误报。工具毕竟是工具,它只能依照为它制定的算法行事,所以会有误报的情形发生。但千万不要轻易认定某一个错误为误报,一定要对错误进行仔细的分析,确定是真正的误报。

    2第三方的代码。BoundsChecker指定的错误发生位置在第三方提供的代码中,包括第三方提供的程序库、DLL、OCX等。对于这种情况,我们也要先进行认真的检查,确定不是由于我们错误的使用第三方的代码引起的。如果最后确定不是我们的原因,则这样的错误报告可以忽略。

    3.5 其他

    还有一点需要强调,使用BoundsChecker对程序进行测试时,需要有程序的源代码。如果没有源码,BoundsChecker虽然也可以打开EXE文件将其执行起来,但得出的测试结果经常是不正确的,因此也就没有太大的意义。

    另外,除了可以在VC++集成开发环境中使用BoundChecker外,从 [开始菜单] 中启动BoundChecker,然后打开经BoundChecker编译连接生成的可执行文件,也可以对程序进行测试,操作方法与集成到VC++集成开发环境中BoundChecker的操作方法是一样的,在此就不赘述了。

    至此,BoundChecker所提供的功能全部介绍完了。


    4 TrueCoverage

    覆盖率对于测试来说是一项重要的数据。在我们执行了针对一个功能模块的所有测试用例后,非常想了解测试对于模块代码的覆盖情况,也就是测试覆盖率到达了多少,以此来判断测试工作是否可以结束,如果还未达到测试目标,如何进一步补充测试用例。

    对于这些问题,如果没有覆盖率统计工具的帮助,而想通过手工来进行,几乎是不可能的。

    TrueCoverage的功能就是统计测试覆盖率,它恰好能为我们就上面这个问题提供帮助。TrueCoverage给出的覆盖率是“语句覆盖”,是最低覆盖强度的覆盖率,所以我们测试的项目,用TrueCoverage统计后,应尽量达到100%的覆盖。

    TrueCoverage的应用阶段为单元测试阶段和集成测试阶段。

    BoundChecker一样,TrueCoverage安装成功后,在你的VC++集成开发环境中,会多出一个名为TrueCoverage的菜单,如下图所示:

    7.jpg

    4-1 TrueCoverageVC++集成开发环境中添加的菜单

    这说明,TrueCoverage已经完好的集成到VC++集成开发环境中了。

    下面开始介绍TrueCoverage的具体使用步骤。

    4.1 使用TrueCoverage

    TrueCoverage使用步骤:

    1 在VC++集成开发环境中,打开你所要测试的项目。

    2 为TrueCoverage构造一个文件夹,方法为:

    首先,点击[ Build/Configurations...]菜单命令。

    其次,在弹出的对话框中点击 Add 按钮。

    然后,在Configuration 编辑框中添入你为TrueCoverage创建的文件夹的名称,这个名称是任意的,比如我们叫做TrueCoverage。

    最后,在 Copy settings from组合框中选中 XXX—Win32 Debug项,然后点击OK按钮,接着点击Close按钮。

    现在,我们已经为TrueCoverage构造好了一个文件夹。

    3 点击[Build/Set Active Configuration…] 菜单命令,选中你刚才为TrueCoverage建的文件夹,然后点击OK按钮。

    4 选择[TrueCoverage/Rebuild All with TrueCoverage] 菜单命令,用TrueCoverage的编译连接器对程序重新进行编译连接。TrueCoverage对程序进行编译连接时生成的中间文件、可执行程序,会放到你刚才为TrueCoverage创建的文件夹下。在这个编译连接过程中,TrueCoverage向可执行程序中插入了一些信息,这也就是 TrueCoverage能够跟踪、统计测试覆盖率的原因。

    5点击[TrueCoverage/Run with TrueCoverage] 菜单命令,TrueCoverage被启动,接着你的程序也被执行起来。现在就可以按照事先已经制定好的测试用例,在程序中逐个进行执行了, TrueCoverage会在后台记录程序的执行覆盖情况。

    TrueCoverage界面中有一个工具条,我们有必要在这里对它做一下说明。如下所示:

    8.jpg

    4-2 运行控制工具条

    这个工具条在程序运行起来后,会由不可用状态变为可用状态。工具条上各按钮功能为:

    按钮1:如果在程序的运行过程中你按下了该按钮,则覆盖率的统计只计算到此,你还可以继续操作程序,但此时对程序的任何操作都不再计入到覆盖率统计中去了。

    按钮2:如果在程序的运行过程中你按下了该按钮,则TrueCoverage会马上显示截止到目前为止的测试覆盖率情况。之后你可以继续操作程序,TrueCoverage会继续在后台记录程序的执行覆盖情况。

    按钮3:如果在程序的运行过程中你按下了该按钮,则TrueCoverage会清除在这之前的覆盖数据,使各项覆盖率的数据均为零。你可以继续操作,TrueCoverage在后台从零开始重新记录程序的执行覆盖情况。

    6 当你退出程序时,TrueCoverage会显示本次操作结束后,程序的执行覆盖情况,包括:整个可执行程序的覆盖情况、每个代码文件的覆盖情况、每个代码文件中每个函数的覆盖情况,对于这些覆盖率统计结果,可以文件的形式进行保存。要想再次执行程序,点击TrueCoverage 中的[Program/ Start]菜单命令即可。

    我们不太可能一次执行完所有的测试用例。TrueCoverage 为我们想到了这一点。在我们每次使用TrueCoverage运行起程序,执行了一些用例,关闭程序,并保存这一次的覆盖率统计结果后, TrueCoverage会询问你是否将本次的测试结果合并到总的覆盖率统计结果中去,一般情况下,我们合并进去就可以了。

    下面介绍一下TrueCoverage的界面,按图中的编号分别给出说明。

    9.jpg

    4-3 TrueCoverage的运行界面

    1:表示程序在某一次执行结束后的测试覆盖情况。双击某一个条目,会在34部分的窗口中显示关于本次覆盖率的详细信息。本图中的情况,表示测试人员执行了两次程序。

    2表示程序当前总的测试覆盖情况,是多个1合并后的结果。双击该条目,会在34部分的窗口中显示关于总覆盖率的详细信息。

    3:该窗口中显示的数据与你当前选中的某一次或总的测试覆盖统计结果相对应(即前面说到的12)。该窗口中显示的数据包括:程序的覆盖率、每个代码文件的覆盖率。更详细的信息显示在窗口4中。

    4:该窗口中显示的数据与你在窗口3中的选择相对应,显示了各个函数的测试覆盖情况。用鼠标双击某一个函数,会显示该函数的源代码,TrueCoverage用不同的颜色标识执行过的和未被执行过的代码,如下图所示:

    10.jpg

    4-4 TrueCoverage用不同颜色标识执行过的和未被执行过的代码

        TrueCoverage 默认情况下,用绿色代表已执行的代码,用红色代表未被执行的代码,用黑色代表不可执行的代码(你可以通过选择TrueCoverage的 [program/setting]菜单命令,在启动的对话框中的setting标签页中进行设置,来改变这种默认情况)。通过这些信息,我们可以有针对性的增加、修改用例,来提高测试覆盖率。

    4.2 对内联函数的处理

    内联函数虽然具有函数的形式,但其机制与函数完全不同,所以,在用TrueCoverage统计测试覆盖率时,对内联函数需要采用不同的处理方式。

    默认情况下,TrueCoverage是不会统计内联函数的执行覆盖率的。如果你需要得到内联函数的覆盖率数据,则需要进行一些额外的设置,具体方法是,在VC++的集成环境中选择[TrueCoverage/TrueCoverage Setting...]菜单命令,弹出如下对话框:

    11.jpg

    4-5 内联函数设置

    选中“Instrument inline function”复选框,点击OK。

    然后选择[TrueCoverage/Rebuild All with TrueCoverage] 菜单命令,重新进行编译连接,对于这个可执行程序,TrueCoverage在其执行过程中就能够记录内联函数的覆盖率数据了。

    4.3 TrueCoverage与BoundsChecker的结合使用

    TrueCoverage与BoundsChecker可以结合起来使用。在[BoundsChecker]和[TrueCoverage]菜单下,都有一个[Rebuild with BoundsChecker and TrueCoverage]项,通过这一菜单命令编译连接生成的可执行文件,在程序运行结束后,能同时得到TrueCoverage和BoundsChecker(FinalCheck)的检测结果。

    但这里有一个限定,那就是:必须由BoundChecker打开该exe程序执行,或是在VC++集成开发环境中通过Debug来运行该exe。这样在执行完程序后,能同时得到TrueCoverage和BoundsChecker(FinalCheck)的检测结果,如果你通过TrueCoverage来执行程序,则只会得到TrueCoverage检测结果。这一点请注意。

    4.4 其他

    BoundsChecker一样,要使用TrueCoverage,一定要有被测程序的源代码。如果没有源码,TrueCoverage无法统计覆盖率。

    除了可以在VC++的集成环境中使用TrueCoverage外,从 [开始菜单] 中启动TrueCoverage,然后打开经TrueCoverage编译连接生成的可执行文件,也可以进行覆盖率的统计,操作方法与集成到VC++集成开发环境中TrueCoverage的操作方法一样,在此不再赘述。

    TrueCoverages的使用介绍到此结束了,该工具对于我们进行测试覆盖率统计、补充测试用例的工作很有用处。




    5 TrueTime

    如何提高代码的运行效率,是开发过程中的一个重要问题。一个应用程序运行速度慢,但不容易找到究竟是在哪里出了问题,所以查找出性能瓶颈的位置是调整代码性能的关键。TrueTime 就是一个对应用程序的运行性能进行分析,查找程序性能瓶颈的工具。

    TrueTime 能够收集、显示应用程序运行性能的相关数据,这些数据包括每个模块(EXE、DLL、OCX等)的运行性能,每一个函数的运行性能,对于有源代码的部分,TrueTime还可以给出每一行代码的运行性能。通过这些数据,我们可以确定系统的性能瓶颈,进一步优化程序的性能。

    值得一提的是,TrueTime 在收集应用程序运行性能数据时,使用了一种叫做“Quantum”的技术。“Quantum”技术能够将你测试的应用程序所包含的线程的运行时间,与操作系统中同时运行着的其他应用程序的线程的运行时间区分开来计算,也就是说,TrueTime只会计算花费在你的应用程序的线程上的时间片。这样一来,在同一台计算机上对同一应用程序的性能测试结果,不会因为在该计算机系统中所运行的程序的多少而改变。所以,只要程序运行的硬件条件不发生改变, TrueTime的测试结果也基本不会变化,所以TrueTime对应用程序性能测试的结果是可复现的。

    TrueTime安装成功后,在你的VC++集成开发环境中,会多出一个名为TrueTime的菜单,如下图所示:

    12.jpg

    5-1 TrueTimeVC++集成开发环境中添加的菜单

    这说明,TrueTime已经完好的集成到VC++集成开发环境中了。

    下面开始介绍TrueTime的具体使用步骤。

    5.1 使用TrueTime

    TrueTime使用步骤:

    1在VC++集成开发环境中打开你所要测试的项目。

    2 为TrueTime构造一个文件夹 ,具体方法是:

    首先,点击[ Build/Configurations...]菜单命令。

    其次,在弹出的对话框中点击 Add 按钮。

    然后,在Configuration 编辑框中添入你为TrueTime创建的构造文件夹的名称,这个名称是任意的。比如我们取名为TrueTime。

    最后,在 Copy settings from组合框中选中 XXX—Win32 Debug项,然后点击OK按钮,接着点击Close按钮。

    现在,我们为TrueTime构造好了一个文件夹。

    3 点击[Build/Set Active Configuration…] 菜单命令,选中你刚才为TrueTime创建的文件夹, 然后点击OK按钮。

    4 选中[TrueTime/Rebuild All with TrueTime] 菜单命令,用TrueTime的编译连接器对程序重新进行编译连接。TrueTime对程序进行编译连接生成的中间文件、可执行程序,都会被放到你为 TrueTime创建的文件夹下。在这个编译连接过程中,TrueTime向可执行程序中插入了一些信息,这也就是TrueTime能够记录程序运行性能的原因。

    5点击[TrueTime/Run with TrueTime] 菜单命令,TrueTime被启动,接着你的程序也被启动并执行起来。

    这时,按照事先制定好的测试用例,执行测试用例。TrueTime会记录下被执行到的程序代码的性能数据。

    TrueTime界面中有一个工具条,它的外观与我们在TrueCoverage中说到的那个工具条完全一样,实现的功能也基本一样,只是在TrueCoverage中,它控制的是覆盖率,在这里,它控制的是性能数据。我们现在来对它做一下说明。如下所示:

    13.jpg

    5-2 运行控制工具条

    这个工具条在程序运行起来后,会由不可用状态变为可用状态。工具条上各按钮功能为:

    按钮1:如果在程序的运行过程中你按下了该按钮,则性能统计只计算到此,虽然还可以继续操作程序,但此时对程序的任何操作都不再计入到性能统计中去了。

    按钮2:如果在程序的运行过程中你按下了该按钮,则TrueTime会马上显示截止到目前为止的性能统计情况。之后你可以继续操作程序,TrueTime会继续在后台记录程序的性能数据

    按钮3:如果在程序的运行过程中你按下了该按钮,则TrueTime会清除在这之前所记录的性能数据,使各项性能数据为零。你可以继续操作,TrueTime 查看(382) 评论(0) 收藏 分享 管理

  • CPPUnit在WIN32平台安装说明

    2007-08-21 23:16:37

     目前,CPPUnit在WIN32平台下仅支持Microsoft Visual C++,而且你的VC++编译器至少应该是6.0版本的。

            使用GUI TestRunner编译运行示例程序的步骤如下:

            在VC++中打开examples/examples.dsw(包含所有的示例) 
            将HostApp设为active project 
            编译之 
            在VC中选择Tools/Customize.../Add-ins and Macro Files,点击Browse... 
            选择lib/TestRunnerDSPlugIn.dll文件,并按ok以注册该附加件(add-ins)
    运行project

    [Project创建结果]

    框架 & 工具:

            cppunit(cppunit.lib):单元测试的框架库,你将用它来编写单元测试。 
            cppunit_dll(cppunit_dll.dll/lib):同上,只是以DLL方式呈现。 
            TestRunner(testrunner.dll):一个MFC的扩展DLL,用来以GUI方式运行单元测试和查看结果。 
            DSPlugIn(lib/TestRunnerDSPlugIn.dll):一个VC++的附加件,为testrunner.dll所使用。有了它之后,你若在MFC TestRunner中双击某个failure,就会启动VC++,打开failure所在文件并定位到某行。 
            TestPlugInRunner:(警告:实验性的)一个VC++应用程序,用以运行测试插件。测试插件就是一个公开特定接口的DLL。该应用程序目前尚未完成(auto-reload特性丢失)。

    所有库文件都被置于lib/目录下。

    [示例]

            CppUnitTestMain:一个实际的测试包(test suite)用来测试CppUnit。使用了TextTestRunner(文本方式的单元测试环境),利用CompilterOutputter进行post-build testing(即在编译结束之后紧跟着进行测试)。在配置中设定连接了cppunit的静态库和动态库。

            CppUnitTestApp:包含了与CppUnitTestMain相同的测试包,但使用了MFC TestRunner(GUI方式的单元测试环境)

            hierarchy : 一个演示如何子类化测试的例子(你也许更愿意使用HelperMacros.h以及宏CPPUNIT_TEST_SUB_SUITE,这种方式更为简洁清晰。本示例已经很久没有更新了)。

            HostApp : 一个用MFC TestRunner演示各种失败测试的例子。也演示了MFC Unicode TestRunner。

            TestPlugIn : 一个演示如何为TestPlugInRunner编写TestPlugIn的例子(实验性的).


    [配置(Configuration)]

            CppUnit和TestRunner带有3种配置。

            Release():多线程DLL,release模式

            Debug(d):Debug多线程DLL,debug模式

            Unicode Release(u):Unicode多线程DLL,release模式

            Unicode Debug(ud):Unicode Debug 多线程DLL,debug模式

            Debug Crossplatform (cd): Debug 多线程DLL,没有使用type_info从类名中提取测试用例的包名。

            对CppUnit而言,当创建dll时,字母“dll” 将被添加到后缀之后。

            括号内的字母标明了添加到库名之后的后缀。例如,debug配置的cppunit静态库名为cppunitd.lib。debug配置的cppunit动态库名为cppunitd_dll.lib.

    [创建(Building)]

            在VC++中打开src/CppUnitLibraries.dsw工作区文件。 
            将TestPlugInRunner设为active project。 
            在'Build'菜单中选择'Batch Build...' 
            在Batch Build对话框中,选中所有的project 并按下build按钮。 
            所有的库文件可以在lib/目录下找到。

    测试(Testing)]

            打开工作区文件examples/Examples.dsw。 
            将CppUnitTestApp设为active project. 
            为你要创建的库选择合适的配置。 
            编译运行project。TestRunner GUI将会出现。

    [库(Libraries)]

            所有编译后生成的库均可在'lib'目录中找到。多数库可以在src/CppUnitLibraries.dsw工作区中创建。

    lib\:

    cppunit.lib : CppUnit静态库“Multithreaded DLL”
    cppunitd.lib : CppUnit静态库“Debug Multithreaded DLL”
    cppunit_dll.dll : CppUnit动态库(DLL)“Multithreaded DLL”
    cppunit_dll.lib : CppUnit动态导入库“Multithreaded DLL”
    cppunitd_dll.dll : CppUnit动态库(DLL)“Debug Multithreaded DLL”
    cppunitd_dll.lib : CppUnit动态导入库“Debug Multithreaded DLL”
    qttestrunner.dll : QT TestRunner动态库(DLL)“Multithreaded DLL”
    qttestrunner.lib : QT TestRunner导入库“Multithreaded DLL”
    testrunner.dll : MFC TestRunner动态库(DLL)“Multithreaded DLL”
    testrunner.lib : MFC TestRunner导入库“Multithreaded DLL”
    testrunnerd.dll : MFC TestRunner动态库(DLL)“Debug Multithreaded DLL”
    testrunnerd.lib : MFC TestRunner导入库“Debug Multithreaded DLL”
    testrunneru.dll : MFC Unicode TestRunner动态库(DLL)“Multithreaded DLL”
    testrunneru.lib : MFC Unicode TestRunner导入库“Multithreaded DLL”
    testrunnerud.dll : MFC Unicode TestRunner动态库(DLL)“Debug Multithreaded DLL”
    testrunnerud.lib : MFC Unicode TestRunner导入库“Debug Multithreaded DLL”
    TestRunnerDSPlugIn.dll : 注册到你的VC++中的附加件。

            注意:当你使用CppUnit DLL(cppunit*_dll.dll)时,你必须连接相关的导入库,并在project中定义预处理标识CPPUNIT_DLL。

    [使用CppUnit]

    编写单元测试:

            为了编写单元测试,你需要连接cppunitXX.lib,此处的XX即所选配置对应的后缀字母。 你必须在你的project中打开RTTI开关(Project Settings/C++/C++ Language)。 CppUnit的include目录必须包含在include查找路径中。你可以通过在Project Settings/C++/Preprocessor/Additional include directories或者Tools/Options/Directories/Include中添加include目录做到这一点。

    简言之:

            打开RTTI开关 
            连接lib/cppunitXX.lib 
            include/ 必须包含在include查找路径中


    使用TestRunner GUI: 
            为了使用GUI的test runner,你需要连接testrunnerXX.lib和cppunitXX.lib,此处的XX即所选配置对应的后缀字母。 你必须在你的project中打开RTTI开关。 文件testrunner.dll必须位于你的应用程序所在的路径(Debug或Release目录,project的dsp文件所在目录,或环境变量PATH中所指定的目录)。 一个最简单的办法是,要么添加一个post-build命令,或者,将位于lib/目录下的testrunner.dll添加到你的project中来,并定制创建步骤,将dll文件拷贝到你的“中间结果”目录(通常是Debug或Release目录)。

            因为TestRunner GUI是一个MFC的扩展DLL,它能够访问当前应用程序的CWinApp。 参数设置将使用应用程序的注册键。这意味着,设置项“最近使用的测试”对每个应用程序而言都是不同的。

    简言之:

            打开RTTI开关 
            连接lib/cppunitXX.lib和lib/testrunnerXX.lib 
            include/必须包含在include查找路径中 
            为了运行你的project,lib/testrunnerXX.dll必须可用


    使用DSPlugIn: 
            你必须在VC++中注册该插件。在Tools/Customize/Add-ins and Macro files中点击browse,并选择lib/TestRunnerDSPlugIn.dll(你可以注册release版或者debug版,都能运行)。

            若VC++正在运行,当你双击一个failure后,VC++将打开相关文件并定位到出错行。

    使用Test Plug In Runner: 
            你的DLL必须导出(export)一个函数,该函数实现了在include/msvc6/testrunner/TestPlugInInterface.h中所定义的接口。作为范例,参见examples/msvc6/TestPlugIn/TestPlugInInterfaceImpl.*。注意:该runner仍处于实验阶段并未作足够多的测试。

Open Toolbar