|
知识路径: > 测试技术的分类 > Web应用测试 >
|
被考次数:1次
被考频率:低频率
总体答错率:34%  
知识难度系数:
|
由 软考在线 用户真实做题大数据统计生成
|
相关知识点:53个
|
|
|
|
|
Web应用开发测试主要指在Web应用的开发阶段,对Web应用的源代码和组件进行测试,保证代码的正确性,组件的功能正常。在后面我们给出一个利用Junit进行Java开发的代码进行单元测试的例子。
|
|
|
|
对Web应用系统的代码测试主要包括以下几个方面:源代码规则分析、链接测试、页面静态对象测试等,下面分别叙述。
|
|
|
|
主要方法是使用基于规则检查的工具,读取输入的源代码,然后将源代码与编码标准或语言规则相对照,以找出存在于两者之间的不一致性,或者存在于源代码当中的潜在错误。从某种意义上说,这类工具与文字处理器中的语法和拼写检查器十分相似。
|
|
|
HTML校验工具通常与下面将要使用的链接验证工具集成在一起,主要有“Watchfire Linkbot”、“ParaSoft SiteRuler”、“Matterform Media Theseus”等软件。另外,互联网上还有很多免费在线验证HTML和检查链接的服务网站,如http://validator.w3.org、http://watson.addy.com等。
|
|
|
|
链接是Web应用系统的一个主要特征,它是在页面之间切换和指导用户去一些不知道地址的页面的主要手段。链接测试可分为三个方面。首先,测试所有链接是否按指示的那样确实链接到了该链接的页面;其次,测试所链接的页面是否存在;最后,保证Web应用系统上没有孤立的页面,所谓孤立页面是指没有链接指向该页面,只有知道正确的URL地址才能访问。
|
|
|
测试方法很简单,就是逐一检查链接的有效性、可达性、正确性等,链接测试可以自动进行,有许多可代替手工操作的链接验证工具,在功能测试部分有所介绍。
|
|
|
|
|
|
. 在当前窗口不能完全显示内容时是否提供滚动条功能;
|
|
|
|
|
主要检查表格能否随浏览器窗口的变化或页面的变化自动调整大小。
|
|
|
|
|
|
|
|
|
由于“组件”的概念被广泛使用,对于Web组件有很多歧义,我们有必要首先明确一下Web组件(Web component)在本书中的定义。
|
|
|
所谓Web组件是指这样一个软件单元:它被用于Web系统中,通常嵌入页面中,有些组件为完成一个特定的功能而存在于Web页面中或服务器上,用户的使用请求可以通过浏览器的解释传递给组件,组件执行的结果经浏览器传递给用户。
|
|
|
Web组件范围是非常广的,随着Web系统设计技术的更新在不断发展着。例如我们常见的Java applet、ActiveX控件、VB脚本、Javascript、各种插件、外接件等都属于此列。随着Web编程技术的更新,越来越多的第三方程序推出了支持Web的组件,例如RealPlayer插件、QuickTime插件等。
|
|
|
对于一般的组件测试来说,可分为外形测试和交互测试,也可称为静态测试和动态测试。由于Web组件的范围十分广泛,相互之间差异较大,其测试方法也因对象不同而有所区别,我们将在后面重点介绍几种组件的测试方法。
|
|
|
|
当用户给Web应用系统管理员提交信息时,就需要使用表单操作,例如用户注册、登录、信息提交等。在这种情况下,我们必须测试提交操作的完整性,以校验提交给服务器的信息的正确性。例如:用户填写的出生日期与职业是否恰当,填写的所属省份与所在城市是否匹配等。如果使用了默认值,还要检验默认值的正确性。如果表单只能接受指定的某些值,则也要进行测试。例如,只能接受某些字符,测试时可以跳过这些字符,看系统是否会报错。
|
|
|
除了测试表单实现的功能,还要检查Form区域的外部表现,如文字环绕、随窗口的大小调整大小等。
|
|
|
|
Cookies通常用来存储用户信息和用户在某应用系统的操作,当一个用户使用Cookies访问了某一个应用系统时,Web服务器将发送关于用户的信息,把该信息以Cookies的形式存储在客户端计算机上,这可用来创建动态和自定义页面或者存储登录等信息。
|
|
|
如果Web应用系统使用了Cookies,就必须检查Cookies是否能正常工作。测试的内容可包括Cookies是否起作用,是否按预定的时间进行保存,刷新对Cookies有什么影响等。
|
|
|
|
由于脚本采用不同的语言编写,脚本的测试可以分为静态测试和动态测试。
|
|
|
静态测试是指手工或利用工具检查脚本的源代码的语法错误、逻辑错误和其他与语言有关的编程错误,通常在单元测试阶段实施,由开发人员执行。有很多基于其他编程和脚本语言的,基于规则的分析器可用来进行静态测试,如检查VB脚本的“Compuware Numega CodeReview”、检查C/C++脚本的“ParaSoft Codewizard”、检查Java的“ParaSoft Jtest”等。
|
|
|
动态测试指对Java、Javascript、VBScript、C/C++或Perl等脚本的功能进行逐一验证。需要特别注意的是,不同的浏览器可能要加一定的插件或补丁才能支持上述的一些脚本。
|
|
|
|
CGI是一种服务器端技术,给予用户一定的交互操作权利。实际上CGI是一种协议,用户可以通过浏览器去实施在服务器上的一些操作,包括运行服务器上的.exe程序。所以测试CGI时,可以在服务器上使用一些监控器查看执行CGI的结果。
|
|
|
同样,CGI也会遇到性能问题,在需要的时候也要对CGI进行性能测试。
|
|
|
|
ASP实际上是一种含有脚本命令的文本文件,以.asp作为文件扩展名,它缺省的输出是HTML或HTML及可在客户端处理的脚本。
|
|
|
测试ASP时,可先作代码检查,发现语法及其他明显的编码错误,然后再用不同的浏览器进行验证,以发现ASP是否工作正常。在测试ASP时需要注意以下几个方面。
|
|
|
. 注意浏览器的缓存问题。缓存设置有时会影响到某些ASP的执行。
|
|
|
. 正确设置超时。超时会导致一些ASP页面失效,从而不能正确执行。
|
|
|
. 一些ASP的性能测试是非常必要的。如可能出现非常频繁的数据库查询等。ASP的性能测试可放到Web应用系统的性能测试中考虑。
|
|
|
|
ActiveX控件是客户端技术,实际上类似于Win32程序中的OCX控件,也是一种很常用的控件,在很多Web系统设计中都会用到。我们在测试ActiveX控件时要注意以下几个方面。
|
|
|
. ActiveX只能用于Windows客户端,如果我们使用诸如Netscape的浏览器时,需要添加相应的插件。
|
|
|
. ActiveX应用是编译后的应用,在用户浏览时需要下载到客户端运行,因此,客户端的安全设置可能会影响到ActiveX控件的使用。测试时需要保证ActiveX控件的签名注册通过验证。
|
|
|
. 由于用户有权拒绝使用ActiveX控件,所以,需要测试在ActiveX控件没有下载时,Web系统的功能受影响的程度。
|
|
|
. 要专门进行ActiveX控件的安装与卸载测试,考察安装与卸载过程是否能顺利进行。
|
|
|
. 测试之前需要确认测试环境中没有旧版本的控件,如果有,一定要卸载后进行重新安装测试。因为ActiveX控件与其他组件不同,在网页更新时不会自动重新安装。
|
|
|
|
越来越多的Web应用采用Java技术开发,下面以Junit为例讨论Java开发的Web应用的单元测试。
|
|
|
Junit Framework是一个被多数Java程序员采用和证实的优秀的测试框架,可以用Junit Framework来编写适应自己开发项目的单元测试程序。Junit的用户指南,重点在于解释单元测试框架的设计方法以及简单的类使用说明,而对在特定的测试框架下如何实施单元测试,如何在项目开发的过程中更新和维护已经存在的单元测试代码没有详细的解释,下面就这两个需要解决的问题进一步说明。
|
|
|
|
Junit附带文档所列举的单元测试带有一定的迷惑性,因为几乎所有的示例单元都是针对某个对象的某个方法,似乎Junit的单元测试仅适用于类组织结构的静态约束,从而使初学者怀疑Junit下的单元测试所能带来的效果。因此,我们需要重新定义如何确定有价值的单元测试,以及如何编写这些单元测试、维护这些单元测试,从而让更多的程序员接受并熟悉Junit下的单元测试的编写。
|
|
|
在进行Junit单元测试框架的设计时,设定了如下三个总体目标:
|
|
|
①简化测试框架的编写,这种简化包括测试框架的学习和实际测试单元的编写;
|
|
|
|
|
从这三个目标可以看出,单元测试框架的基本设计考虑依然是从我们现有的测试方式和方法出发,而只是使测试变得更加容易实施、扩展并保持持久性。因此编写单元测试的原则可以借鉴和利用我们通常使用的测试方法。
|
|
|
|
在通常的测试中,一个单元测试一般针对于特定对象的一个特定特性,例如,假定编写了一个针对特定数据库访问的连接池的类包实现,则要建立以下的单元测试。
|
|
|
. 在连接池启动后,是否根据定义的规则在池中建立了相应数量的数据库连接;
|
|
|
. 申请一个数据库连接,是否根据定义的规则从池中直接获得缓存连接的引用,还是建立新的连接;
|
|
|
. 释放一个数据库连接后,连接是否根据定义的规则被释放以便以后使用;
|
|
|
. 后台Housekeeping线程是否按照定义的规则释放已经过期的连接申请;
|
|
|
. 如果连接有时间期限,后台Housekeeping线程是否定期释放已经过期的缓存连接。
|
|
|
这里只列出了部分的可能测试,但是可以看出单元测试的粒度。一个单元测试基本是以一个对象的明确特性为基础,单元测试的过程应该限定在一个明确的线程范围内。根据上面所述,一个单元测试的测试过程非常类似于一个Use Case的定义,但是单元测试的粒度一般来说比Use Case的定义要小,这点是容易理解的。因为Use Case是以单独的事务单元为基础的,而单元测试是以一组聚合性很强的对象的特定特征为基础的。一般而言,一个事务中会利用许多的系统特征来完成具体的软件需求。
|
|
|
从上面的分析可以得出,测试单元应该把一个对象的内部状态的转换为基本编写单元。一个软件系统就和一辆设计好的汽车一样,系统的状态是由同一时刻系统内部的各个分立的部件的状态决定的,因此为了确定一个系统最终的行为符合要求,我们首先需要保证系统内的各个部分的状态会符合我们的设计要求,所以我们的测试单元的重点应该放在确定对象的状态变换上。
|
|
|
然而,需要注意的并不是所有的对象组特征都需要被编写成独立的测试单元,应该在有可能引入错误的地方引入测试单元,通常这些地方存在于有特定边界条件、复杂算法以及需求变动比较频繁的代码逻辑中。除了这些特性需要被编写成独立的测试单元外,还有一些边界条件比较复杂的对象方法也应该被编写成独立的测试单元,这部分单元测试已经在Junit文档中被较好地描述和解释过了。
|
|
|
在基本确定了需要编写的单元测试之后,我们还应该问自己:编写好了这些测试,我们是否可以有把握地告诉自己,如果代码通过了这些单元测试,我们能认定程序的运行是正确的,符合需求的。如果我们不能非常地确定,就应该看看是否还有遗漏的需要编写的单元测试,或者重新审视我们对软件需求的理解。通常来说,在开始使用单元测试的时候,大多数单元测试总是没有错误的。
|
|
|
一旦我们确定了需要编写的测试单元,接下来就应该着手编写。
|
|
|
|
通常强调单元测试必须由类包的编写者负责编写,这个限定对于我们设定的测试目标是必须的。因为只有这样,测试才能保证对象的运行行为符合需求,而通过类接口的测试,我们只能确保对象符合静态约束,因此这就要求我们在测试的过程中,必须开放一定的内部数据结构,或者针对特定的运行行为建立适当的数据记录,并把这些数据暴露给特定的测试单元。这也就是说我们在编写单元测试时必须对相应的类包进行修改,这样的修改也发生在我们以前使用的测试方法中,因此,以前的测试标记及其他一些测试技巧仍然可以在Junit测试中改进使用。
|
|
|
由于单元测试的总体目标是保证软件在运行过程中的正确无误,因此在我们对一个对象编写单元测试的时候,我们不但需要保证类的静态约束符合我们的设计意图,而且需要保证对象在特定条件下的运行状态符合我们的预先设定。下面还是拿数据库缓冲池的例子进行说明。一个缓冲池暴露给其他对象的是一组使用接口,其中包括对池的参数设定、池的初始化、池的销毁、从这个池里获得一个数据连接,以及释放连接到池中,对其他对象而言,随着各种条件的触发而引起池的内部状态的变化是不需要知道的,这一点也是符合封装原理的。但是池对象的状态变化,例如缓存的连接数在某些条件下会增长,一个连接在足够长的运行后需要被彻底释放,从而使池的连接被更新等,虽然外部对象不需要明确,但是却是程序运行正确的保证,所以我们的单元测试必须保证这些内部逻辑被正确地运行。
|
|
|
编译语言的测试和调试是很难对运行逻辑过程进行跟踪的,但是我们知道,无论逻辑怎么运行,如果状态的转换符合我们的行为设定,那么结果显然是正确的。因此,在对一个对象进行单元测试的时候,我们需要对多数的状态转换进行分析和对照,从而验证对象的行为。状态是通过一系列的状态数据来描述的,因此编写单元测试,首先分析出状态的变化过程(状态转换图对这个过程的描述非常清晰),然后根据状态的定义确定分析的状态数据,最后是提供这些内部的状态数据的访问。在数据库连接池的例子中,我们对池实现的对象“DefaultConnectionProxy”的状态变换进行分析后,我们决定把表征状态的“OracleConnectionCacheImpl”对象公开给测试类。参见示例1。
|
|
|
|
|
|
为了能够了解对象的状态变化,需要给表征对象内部状态变化的部分私有变量提供公共的访问接口(或者提供让同一个类包访问的接口),以便使测试单元可以有效地判断对象的状态转变,在本示例中对包装的OracleConnectionCacheImpl对象提供访问接口。
|
|
|
|
在公开内部状态数据后,我们就可以编写我们的测试单元了。单元测试的选择方法和选择尺度已经在前面章节进行了说明。但是仍然需要注意的是,由于assert方法会抛出一个error,你应该在测试方法的最后集中用assert相关方法进行判断,这样可以确保资源得到释放。对数据库连接池的例子,我们可以建立测试类DefaultConnection-ProxyTest,同时建立数个测试案例,如下所示。
|
|
|
|
|
|
|
当单元测试完成后,我们可以用Junit提供的TestSuite对象对测试单元进行组织,你可以决定测试的顺序,然后运行你的测试。
|
|
|
|
通过上面的描述,我们对如何确定和编写测试有了基本的了解,但是需求总是变化的,因此我们的单元测试也会根据需求的变化不断地演变。如果我们决定修改类的行为规则,必然会对这个类的测试单元进行修改,以适应变化。但是,如果对这个类中仅有调用关系的类的行为定义没有变化,则相应的单元测试仍然是可靠和充分的,同时如果包含行为变化的类的对象的状态定义与其没有直接的关系,测试单元仍然起效。这种结果也是封装原则的优势体现。
|
|
|