自动化测试异常处理与用例管理

上传人:小** 文档编号:48868546 上传时间:2022-01-15 格式:DOC 页数:20 大小:557.50KB
返回 下载 相关 举报
自动化测试异常处理与用例管理_第1页
第1页 / 共20页
自动化测试异常处理与用例管理_第2页
第2页 / 共20页
自动化测试异常处理与用例管理_第3页
第3页 / 共20页
点击查看更多>>
资源描述
测试用例的前置条件和后置条件除了第二点中谈到的数据需要准备外,在测试用例这个Level,必须有一些条件满足,您才能开始执行它。比如准备一个初始设置条件下的IE浏览器和已安装过老版本该软件的XP系统。这些可重用的准入条件,可以考虑不作为特定用例的Step,而是把它提取出来,作为Setup Section或叫 Pre-Condition。对于后置条件或Post- condition,往往我们用它来做一些处理或恢复,比如在上面的取款例子中,如果我们要用相同的帐号重复测试,在正好取完所有金额,余额为零的情况下,可以通过一些步骤或数据库脚本重置帐号余额。同样,您为某个用例设置浏览器禁用了Cookie,执行完该用例后,是不是也是需要回复到默认设置的状态呢?集中的把这些步骤整理成一个相对独立的操作单元,具体用例中只要引用就可以了,这样会便于对用例的理解和在多处复用。顺便说一下,对于一些类似软件运行环境的条件,比如安装和配置测试中,需要3种操作系统和3种浏览器的组合等,我们可以把他放在Test Set这个Level上来,不用写多个用例,只是在测试计划和执行的管理系统中作为测试集的一个环境参数,恰当地表达出来就可以。4. 常用业务操作(Knowledge Base)对于一个大型的应用,比如银行系统,开发和测试工作是长期的,持续的一个过程,这样的系统很适合引入自动化测试。它业务逻辑复杂, 测试技术性要求高,往往使用了不同厂商的工具和多种脚本语言(如 Shell,Python等),也存在了很多可用的遗留脚本。这些完成一些预定业务操作的脚本单元,是可以直接借用的。为了在公司和产品层面,管理好这些可复用的资源,一种好的方式是给它们标 上号,如KB_PRJ01_Module02_XXX,集中管理起来,以后的用例中只要调用即可。举例来说,在银行业务测试中我们,需要模拟和银联的接口,让测试帐号向外汇款,取得响应信息,并保存结果,这可能是个复杂而底层的 处理过程,对一般员工是不需要,也没有权限去深入掌握的。这时,将他们包装成一个个Shell脚本或小工具,做好使用说明和统一建档,在以后的项目测试中,只要调用就可以了。如此,可以大大提高各个有相关接口的模块的自动化测试工作效率。根据以往工作中常见的一些问题,对于如何写好测试用例(不仅针对自动化测试),做以下做几点补充:推荐不推存将用例的内容描述清楚,强调怎么操作,验证什么,然后期待的结果是什么。Copy需求和设计文档中的内容;描述成:什么 条件下,逻辑会是怎样。这样对测试用例的阅读 和执行人员,不具有可操作性。期待的结果要与具体,如:系统反应是什么;结 果数字是多少;用户被带到什么页面; 显示什么 成功信息;后台或数据库中该记录的修改后结果 是怎么样的。描述成:”验证系统返回正确结果“”页面兀素 显示跟SPEC-致:”操作成功等比较抽象的说 法。业务逻辑性较强的应用软件,做到以业务流为主线,来组织用例。以页面形式组织用例。以Module、Function、测试类型、基本业务流、备选业务流的树状结构形式,分层次组织用例; 使用用例管理工具。Word格式的扁平组织结构,不利于管理和阅读。用一个属性字段,建立用例和Spec等文档的某个章节间的映射。无法和需求对应,以后难以计算用例覆盖率,测 试执行覆盖率。每个Module、Function、特定业务的一组测试用 例,之间做到独立、没有耦合。用例之间有依赖,无法做到:挑选30%的用例做 回归测试。在时间和成本允许的情况下,尽量做到:用例粒度为一种不同的操作,得到不同的结果,就单 独写一个用例。在用例中的操作步骤中, 甚至期待结果中,仍然 存在条件分支。对于复杂的业务操作过程,如”一次顺序的表单 签核过程和” 一次完整的信贷手续,单独增加 一些贯穿整个业务流的大型测试用例。对于一个长业务操作,只存在比较零散的细节用 例。将用例分优先等级,便于在回归测试时挑选核心 业务或用户操作密集的用例。用例没有优先级和重要程度的定义。自动化测试用例设计的原则很多公司在实施自动化测试的过程中, 往往会把所有的手工测试用例作为自动化测试用例, 并且直接进行脚本的开 发工作,甚至有些公司不写自动化测试用例,直接想当然地开发测试脚本,这些都是极其不规范的做法,甚至很有可能 是导致最后自动化测试项目失败的最大原因。那么问题就来了,为什么不能使用手工测试用例完全替代自动化测试用例 呢?有以下几点原因,同时也是自动化测试用例的设计原则原则1:自动化测试用例的范围往往是核心业务流程或者重复执行率较高的。在选取自动化测试用例范围时,很多测试工程师或者上级领导可能心里会过分依赖自动化测试,会认为自动化测试 就应该覆盖所有的手工测试用例,自动化测试的覆盖率就应该达到百分之百。其实恰好相反,这样的想法往往会导致自 动化测试最终失败。在一些大型项目中,往往测试用例的数量会很庞大,而且如果遇到一些繁杂的被测程序(特别是C/S架构),脚本开发工作往往会相当耗时间,并且很多测试用例甚至根本就不能通过自动化来实现。举些例子,现在很 多公司自动化测试都是刚起步,对自动化测试的了解程度只是停留在字面上,在公司对测试也不是非常重视的情况下, 当然不太愿意去花精力招一个具有自动化测试开发经验的工程师,很多还是停留在使用工具的录制回放功能来完成自动 化测试。正是存在这样的技术限制情况下,往往在实施中,会出现很多录制回放不能解决的问题,测试工具完全无法识 别测试对象,无法识别一些特殊的加密测试控件。还有,如果项目的变更频率,测试用例数量大的话,增加了后期的维 护工作量等,都是造成最终失败的一些隐患。投入越大,损失越大。因此,往往我们会选取最核心的一些业务路径或者 是重复执行率较高的一些手工测试用例进行自动化测试,这样能够充分发挥出自动化测试的优势。原则2:自动化测试用例的选择一般以正向”为主。手工测试用例分正常情况和异常情况,在设计的时候,可能往往会去设计很多异常情况来验证程序是否有Bug,并且一个正常情况的测试用例往往会对应几十个非正常情况的测试用例,而每种异常情况的测试用例都会有各种各样的预 期结果。在自动化测试中,很多人喜欢将正常情况称为 正向”反之,异常情况则称为 反向”下面,我们试想以下,如 果将这些异常情况全部转化、反应到自动化测试脚本中,那肯定需要非常繁琐的判断才能做到。这个对于自动化测试工 程师来说,其现有的工作量还是今后的脚本维护量都是不可小视的。对于整个自动化测试项目来说,如果每个异常情况 都要写进脚本中,那真的是花了大价钱买一堆小东西,小东西真正能发挥大作用的毕竟很少。因此,真正在自动化测试 项目实施中,往往会舍弃反向用例,个别比较重要的除外。使每个东西都能发挥其最大的作用才是企业最想看到的。功 能自动化测试主要还是用于回归测试,回归测试的目的就是保证新增功能后老功能是否能够正常继续运作。而自动化测 试则是让测试人员从繁琐又枯燥的重复手工测试中解放出来,这就是目的和目标。原则3:不是所有手工测试用例都可以使用自动化测试来实现的。这里纠正许多测试从业人员的一个错误观念,刚接触测试自动化的普遍都会认为手工测试用例全部要转化为自动化 测试用例,但是在真正实施的时候,却发现很多测试用例是自动化无法实现的,或者有些测试用例根本就没有必要去自 动化的。例如,有些用例会牵涉到硬件设备辅助的,最简单的例子就是用例执行过程中需要使用刷卡机才能获取卡号信 息(如果有技术能力,当然不排除自行开发接口供测试工具调用,但毕竟能有技术实力做到这一步的不多,能有这样的 重视程度的更不多);再比如,有些测试用例是需要与合作机构进行互动联调,联调时是需要和对方实时沟通,以及根 据具体情况给予响应的,这些情况多数还是只能使用手工人为地来完成。当然,决定是否转化为自动化测试,必须事先 有一个规范文档来定义哪些是需要转化为自动化测试哪些是不需要的,否则测试工程师就会不知所措,没有一个标准。 一旦有了这个标准,自动化测试工程师就可以严格按照文档里的流程去完成需要转化部分的自动化测试用例的脚本开发 工作了。原则4:手工测试用例可以不用回归原点,而自动化用例往往是必须的。很多有经验的自动化测试从业人员一定有这样的经历,很多时候脚本写完后,第一次执行没有任何问题,而第二次 执行时立刻就会报错,原因就是没有回归原点。所谓回归原点就是执行的测试用例最终需要恢复其在执行前的初始状态, 如果没有回归原点,就会把此脚本称之为死脚本。举个最简单的例子,比如添加用户功能,我们都知道每个用户名都是 唯一的,当写完一个添加用户的脚本之后,执行第一次没有问题,因为执行前此用户还不存在,但是当执行第二次时, 程序就会出现用户重复而报错,此时这个添加用户的脚本就失去了它的价值,在这种情况下,我们就需要在自动化测试 用例的最后加上删除这个用户的步骤,这样在下次执行用例时就不会出现用户重复的情况了。当然,除了回归原点,还 可以使用另一种方式进行,那就是初始化数据,比如 ATM机取款,假设需要执行取款100元的操作,而银行卡余额是 120元,当测试脚本第一次执行时可能没有任何问题,但是第二次系统就会报余额不足,这样就成为了死脚本,解决方 案有两种:一种是直接进行初始化数据,每次执行用例之前都重置下余额(只需大于100即可);第二种方法可以在用例执行前,先查询下余额是否大于100,若大于等于则继续,若小于则做一笔充值 100的操作,这样即可解决。两种方 式可以看具体情况使用,数据初始化方便,但有时候初始化之后可能会影响到其他自动化测试用例的执行,而第二种方 式相对在脚本上需要稍微花点功夫。究竟使用哪种方式还需要具体情况具体分析。总之,在执行自动化测试用例之前做 好数据准备,这也是自动化测试的关键步骤。原则5:自动化测试用例和手工测试用例不同,不需要每个步骤都写预期结果。在手工测试用例的设计过程中,几乎每一个测试步骤都有一个预期结果。但是,在自动化测试用例的设计中并不采 用,在自动化测试用例中,只有准备在测试脚本中设置成检查点的步骤才有预期结果,其他所有的步骤只将它看作一个 步骤,这样做的好处是一目了然、目的明显、层次分明,以后写测试脚本直接跟着自动化测试用例就行了。因为经过前 面的探讨应该已经知道,自动化测试中并不是所有的东西都需要验证的。所以,作者在前面的章节中也提到过,基本上 手工测试用例多多少少都要进行一些转换的,就是因为它们之间的格式是不一致的。举一个简单的例子,假设需要设计 一个注册页面的自动化测试用例,有10几个表单需要填写,在手工测试用例中,每个表单的填写都一定会有预期结果, 因为它的确在检查每一项是对了还是错了,只是用的是你的眼睛在检查而已,所以速度非常的快,甚至你自己潜意识都 忽略了其实你已经检查了。但是,在自动化测试中,我们知道如果你要检查,那一定需要写代码,如果每项都检查,那 代码量有多大是可想而知的,不是说做不到,只是这样做根本不符合自动化测试的特点。所以,绝大部分时候,这些在 自动化测试中可有可无的检查,我们全部 不检查”只当做一个业务流程和步骤,是不需要设立预期结果的。难以对于UI样式或UI逻辑进行断言以上图为例,有一个UI样式类的缺陷(左侧菜单树的根节点“console下面多出来一条虚线)和一个UI逻辑类的缺陷(右 侧用户列表只有一页,但 下一页和最后一页”图标依然是可以点击的,即没有灰显)。此类缺陷即使对于经验丰富、心 思缜密的测试人员,在人工测试时也是很可能发现不了的,并且在自动化测试过程中也很难进行断言。即使存在上述问题,测试脚本中是否有充分的断言,依然是评判自动化测试有效性的一个重要指标。但实施过自动化测 试的人应该都会有这样的体会:大部分断言在大部分情况下只是佐证软件是运行正常的 ”当然,所有人都应该是非常期待看到这样的结果,毕竟谁也不希望每次回归测试时都是用例大面积不通过。只是辛辛苦 苦写这些断言语句的测试人员心里未免有些 小遗憾”。本系列上篇文章中谈到 很多人一提到自动化测试脚本,马上就想到需要提供录制工具”,但如果换个角度思考,很可能就是柳暗花明又一村”。在这里,我们同样换个角度思考,假设我们的自动化测试主要目标是为了证明软件运行正常,那么我们会怎么做?笔者这边的一个经验就是 按照完整的业务流程来组织测试用例,只对少量、必要的关键点进行断言”。以租户对虚拟化资源的申请使用”为例,来具体看看测试用例的组织方式:1. 新租户注册;2. 管理员登录系统,对注册租户进行审批,然后退出系统;3. 审批后的租户登录系统;4. 租户申请所需要的虚拟化资源(比如,40G硬盘、2核CPU、2G内存),然后退出系统;5. 管理员登录系统,对租户申请的资源进行审批,然后退出系统;6. 租户登录系统,在已申请资源的基础上创建安装指定操作系统的虚拟机;7. 断言虚拟机是否创建成功;8. 租户退出系统;9. 管理员登录系统,删除租户;10. 断言租户之前申请的资源是否被完全释放;11. 租户再次登录系统,断言是否无法登录;上述测试用例就是按照完整的业务流程进行组织,并且只对少量关键点(7、10、11 )进行断言,如果整个用例可以运行通过,就能证明这个业务是没有问题的。另外还有一个值得考虑的现象,就是相对于自动化测试而言,一个优秀的测试人员在人工测试时是如何判断功能正确与 否的呢?他不会死板的只盯着某几个输入域的值,他一定还会同时关注页面上所有数据的正确性、会更加关注业务流程 是否正确、会更敏锐的发现页面样式或 UI逻辑类的缺陷。为了兼顾证明软件正常运行”和人性化的识别软件缺陷”,一个优秀的测试工具应该考虑提供以下多种断言机制。一、控件级细粒度断言即前面提到的最常见的断言方式。在测试过程中,可以在任何位置增加断言脚本,来判断页面指定控件是否存在、控件 显示值是否为预期结果等。通常建议只对关键校验点进行断言。二、页面级粗粒度断言通过对比前(之前测试通过)后(后续持续发布)版本在测试用例路径和输入参数相同的情况下,整个页面内容(包括 截图和数据)是否严格相同来做粗粒度断言。通过页面截图进行断言有两个实现要点:首先要选择一个合适的截图方案(笔者推荐采用Selenium WebDriver提供的TakesScreenshot接口);其次需要提供图片对比工具,以便测试人员可以一眼看出两个版本页面截图的差异。下面是笔者在测试框架中实现的截图自动化对比功能的实际效果。下图中左侧部分是实际结果截图”、右侧是 预期结果截图”、中间部分是差异对比,测试人员一眼便可看出其中的Bug :表格行选中的翻页缓存(在当前页选中几条记录,翻到下一页再翻回本页,需要保持之前的行选中状态)功能丢失了”。通过页面数据进行断言的实现方式相对简单一些,首先要提取页面上所有的数据(或文本),接着进行格式化,然后再 自动化对比。页面级粗粒度断言”的特点及应用场景如下: 无需编写任何断言语句; 需要能够提供可用于自动对比的历史正确版本,特别适用于可以持续构建的项目; 能判断出UI样式和UI逻辑类的错误;. 由于对比绝对精准,导致可能存在误判,因此需要人工对差异图片进行排查;【注】由于很多Web页面都有渐入渐出、点击时按钮变色等很炫的效果,所以在两次截图的瞬间可能页面的动态样式是不一样的,这就是 所谓的误判”。笔者对于一个动态样式”适中的项目采用这种断言方式,统计结果表明误判率在20%左右。 鉴于回归测试的时候,通常大部分用例应该是可以通过的,所以页面级粗粒度断言”的投入产出比非常占优势!三、基于业务逻辑断言在测试设计时把有依赖关系的用例一起执行,如果某个步骤出现问题,即便不设置任何断言语句,在当前步骤或后续步 骤的测试用例也会执行失败。下面以 增加、查询、修改、删除”这个最典型的流程来说明(如下图所示)。測试用例:在“壇加1*出错时可能的斷言结果删除记录A1測试用例:在“壇加1*出错时可能的斷言结果假定在 增加”环节出现问题,那么我们的测试用例执行情况可能出现如下几种结果:1. 如果在增加记录A”的用例中包含对是否增加成功的断言,那么测试用例从增加记录A”开始出错;2. 如果在增加记录A”中不包含断言,而是在查询A”的用例中包含是否有查询结果的断言,那么测试用例会从 查 询A”开始出错;3. 如果在查询A”中也不包含断言,那么测试用例会从 修改查询结果”开始出错。所谓基于业务逻辑断言”,就是指上述第三种情况,其特点及应用场景如下: 无需编写任何断言语句,但测试设计要考虑业务逻辑顺序; 与页面级粗粒度断言”相比,不需要提供可用于对比的历史正确版本,通常适用于项目刚开发或样式做整体调 整等情况;* 断言错误的位置不精准,可能延后; 执行过程每一步都做截图备份(通过 Selenium WebDriver可以很方便的实现),可以非常有效的辅助定位准 确的出错原因;鉴于回归测试的时候,通常大部分用例应该是可以通过的,所以基于业务逻辑断言”的投入产出比非常占优势!四、自定义扩展断言在人工测试时经常有些操作结果的正确与否在当前页面无法做出判断,需要到其它页面甚至系统外部(比如,数据库、 输出日志)获取信息来做出判断。以最常见的 基于数据库进行断言”为例,测试工具需要支持把断言时用到 预期结果 和实际结果”己置为对应的SQL语句。以上介绍了从测试工具的角度可以提供的多种断言机制,在自动化测试过程中应该根据项目实际情况,考虑采用上述多 种断言的组合,以弥补控件级细粒度断言的不足。ASP.NET MVC集成EntLib实现自动化”异常处理实例篇个人觉得异常处理对于程序员来说是最为熟悉的同时也是最难掌握的。说它熟悉,因为仅仅就是try/catch/finally而已。说它难以掌握,则是因为很多开发人员却说不清楚try/catch/finally应该置于何处?什么情况下需要对异常进行日志记录? 什么情况下需要对异常进行封装?什么情况下需要对异常进行替换?对于捕获的异常,在什么情况下需要将其再次抛出? 什么情况下则不需要?合理的异常处理应该是场景驱动的,在不同的场景下,采用的异常处理策略往往是不同的。异常处理的策略应该是可配 置的,因为应用程序出现怎样的异常往往是不可预测的,现有异常策略的不足往往需要在真正出现某种异常的时候才会 体现出来,所以我们需要一种动态可配置的异常处理策略维护方式。目前有一些开源的异常处理框架提供了这种可配置 的、场景驱动的异常处理方式,EntLib的Exception Handling Application Block (以下简称EHAB )就是一个不错的选择。源代码从这里下载本文已经同步到How ASP.NET MVC Works?中目录一、通过指定 Handle-Error-Action 响应请求二、通过Error View显示错误消息三、自动创建 JsonResult响应Ajax请求一、通过指定 Handle-Error-Action 响应请求在正式介绍如何通过扩展实现与 EntLib以实现自动化异常处理之前,我们不妨先来体验一下异常处理具有怎样的自动化”特性。以用户登录场景为例,我们在通过 Visual Studio的ASP.NET MVC项目模板创建的 Web应用中定义了如下 一个简单的数据类型LoginInfo封装用户登录需要输入的用户名和密码。1: public class LoginInfo2: 3:DisplayName(用户名)4:Required(ErrorMessage=请输入0)5:public string UserName get; set; 6:7:DisplayName(密码)8:Required(ErrorMessage=请输入0)9:DataType(DataType.Password)10:public string Password get;set;11: 然后我们定义了如下一个 HomeController。基于HTTP-GET的Action方法Index将会呈现一个用户登录 View,该View使用创建的Logininfo对象作为其Model。真正的用户验证逻辑定义在另一个应用了HttpPostAttrubute特性的Inde x方法中:如果用户名不为 Foo,抛出InvalidUserNameException 异常;如果密码不是 “password”则抛出InvalidPasswordException 异常。InvalidUserNameException 和 InvalidPasswordException 是我们自定义的两种异常类型。1:2:3:4:5:6:7:8:9:10:11:12:13:14:15:16:17:18:19:20:21:22:23:24:25:26:27:28:29:30:ExceptionPolicy(defaultPolicy)public class HomeController : ExtendedControllerpublic ActionResult Index()return View(new LoginInfo();HttpPostHandleErrorAction(OnIndexError)public ActionResult Index(LoginInfo loginInfo)if (string.Compare(loginInfo.UserName, foo, true) != 0)throw new InvalidUserNameException。;if (loginInfo.Password != password)throw new InvalidPasswordException();return View(loginInfo);HttpPostpublic ActionResult OnIndexError(LoginInfo loginInfo)return View(loginInfo);上面定义的HomeController具有三点与自动化异常处理相关的地方: HomeController继承自自定义的基类ExtendedController,后者完成了对异常的自动化处理。* HomeController类型上应用了自定义的ExceptionPolicyAttribute特性用于指定默认采用的异常处理策略名称(“defaultpolicy)。 基于 HTTP-POST 的 Index 方法上应用了 HandleErrorActionAttribute 特性用于指定一个 Handle-Error-Action 名称,当异常在目标Action执行过程中抛出并通过EHAB处理后,指定的Action会被执行以实现对请求的响 应。对于我们的例子来说,从Index方法抛出的异常被处理后会调用OnlndexError方法作为对当前请求的响应。下面是代表登录页面的 View的定义,这是一个 Model类型为LoginInfo的强类型View。在该View中,作为Model的 LoginInfo对象以编辑默认呈现在一个表单中,表单中提供了一个 登录”提交表单。除此之外,View中还具有个Validati onSummary。1: model LoginInfo2: 3:4: 用户登录 5:6:.validation-summary-errorscolor:Red7:8:9:10:using (Html.BeginForm()11:12:Html.ValidationSummary(true)13:Html.EditorForModel()14:15:16:17:通过 HomeController 的定义我们知道两种不同类型的异常(InvalidUserNameException 和 InvalidPasswordException )分别在输入无效用户名和密码是被抛出来,而我们需要处理的就是这两种类型的异常。正对它们的异常处理策略定义在 如下的配置中,策略名称就是通过应用在HomeController上的ExceptionPolicyAttribute 特性指定的“defaultpolicy。1: configuration2:3:5:6:7:8:9:10:11:12:13:14:15:16:17:18:19:20:21:22:23:24:25:.26: /configuration通过上面的这样异常策略配置可以看到:我们使用一个自定义的名为ErrorMessageHandler的ExceptionHandler来处理抛出来的 InvalidUserNameException 和 InvalidPasswordException 异常,而 ErrorMessageHandler 仅仅是指定一个友好的错误消息,该消息一般会呈现给最终的用户。运行该程序后一个用于登录页面会呈现出来,当我们输入错误的用户名和密码的时候,相应的错误消息(在配置中通过ErrorMessageHandler设置的错误消息)会以如图7-16所示的效果显示出来,其实整个 View是通过执行Action方法OnIndexError返回的ViewResult呈现出来的。、通过Error View显示错误消息除了通过执行对应的Handle-Error-Action来呈现异常处理后的最终结果之外,还支持错误页面的错误呈现方法。简单起见,我们只是用名称为Error的View来作为最终的错误页面。为了演示基于错误页面的呈现方式,我们按照如下的方式重新定义了目录下的 Error.cshtml。1:model ExtendedHandleErrorlnfo2:3:Layout = null;4:5: VDOCTYPE html6:7:8:9:Error10:11:h3 color:Red;12:13:14:15:16:17:18:19:Controller: Html.DisplayFor(m = m.ControllerName)20:Action: Html.DisplayFor(m = m.ActionName)21:Exception:22:23:Message: Html.DisplayFor(m = m.Exception.Message)24:Type: Model.Exception.GetType().FullName25:StackTrace: Html.DisplayFor(m = m.Exception.StackTrace)26:27:28:29:30:Html.DisplayFor(m=m.ErrorMessage)上面这个 View的Model类型是具有如下定义的 ExtendedHandleErrorInfo。它继承自HandleErrorlnfo,只额外定义了 一个表示错误消息的ErrorMessage属性。在上面的这个View中,我们将错误消息、异常类型和 StackTrace和当前C ontroller/Action的名称呈现出来。1: public class ExtendedHandleErrorInfo : HandleErrorInfo2: 3:public string ErrorMessage get; private set; 4:public ExtendedHandleErrorInfo(Exception exception, string controllerName, string actionName, stringerrorMessage)5:base(exception, controllerName, actionName)6:7:this.ErrorMessage = errorMessage;8:9: 当利用EntLib的EHAB对从Index方法中抛出的异常进行处理后采用错误View的方式来响应请求,我们需要按照如下的方式将应用在该方法上的HandleErrorActionAttribute 特性注释掉。1: ExceptionPolicy(defaultPolicy)2: public class HomeController : ExtendedController3: 4:其他成员5:HttpPost6:HandleErrorAction(OnlndexError)7:publicActionResult lndex(LoginlnfologinInfo)8:9:省略实现10:11: 再次运行该程序并分别输入错误的用户名和密码后,默认的错误View( Error.cshtml )将会以如下图所示地效果把处理后的异常结果呈现出来。* Atu Miri*i T仪* S-WklPAT* ftwKn IdHprwr:扌矶Fdhei EimL u 殊血电 .wqpul.i k * Efnltaf h l 輕rp如n( Ll.Litt t iltf 10: 三、自动创建 JsonResult响应Ajax请求 用于实施认证的Action方法Index可以通过普通的HTTP-POST的形式来调用,同样也可以通过 Ajax请求的方式来调用。对于Ajax请求来说,我们最终会将通过 EntLib处理后的异常封装成如下一个类型为 ExceptionDetail的对象。如下 面的代码片断所示,ExceptionDetail具有与Exception对应的属性设置。最终根据抛出异常对象创建的 ExceptionDetai l对象会被用于创建一个JsonResult对象对当前Ajax请求予以响应。1: public class ExceptionDetail2: 3:public ExceptionDetail(Exception exception,string errorMessage=null)4:5:this.HelpLink =exception.HelpLink;6:this.Message =string .I sNullOrEmpty(errorMessage) ? exception.Message : errorMessage;7:this.StackTrace= exception.StackTrace;8:this.Type = exception.GetType().ToString();9:if (exception.InnerException!= null)10:11:this .In nerException = new ExceptionDetail(exceptio n.In nerException);12:13:14:15:public string HelpLink get; set; 16:public ExceptionDetail InnerException get; set; 17:public string Message get; set; 18:public string StackTrace get; set; 19:public string Type get; set; 20: 当客户端接收到回复的Json对象后,可以通过检测其是否具有一个 ExceptionType属性(对于一个ExceptionDetail 对象来说,该属性不可能为 Null)来判断是否发生异常。作为演示我们对 Action方法Index对应的View进行了如下的 改动。1: model LoginInfo2: 3:4: 用户登录 5:1:2:1: 2:3:function login(data) 4:if (data.ExceptionType) 5:alert(data.Message);6:10:7:else 8:alert(”认证成功);9:11:6:7:8:6:10:9:AjaxOptions options = new AjaxOptionsOnSuccess = login;6:10:6:10:10:6:10:11:using (Ajax.BeginForm(options)6:10:6:10:12:6:10:13:14:Html.EditorForModel()6:10:6:10:15:16:17:如上面的代码片断所示,我们通过调用AjaxHelper的BuginForm生成了一个以Ajax形式提交的表单。表单成功提交(服务端因对抛出的异常进行处理而返回一个封装异常的Json对象,对于提交表单的Ajax请求来说依然属于成功提交)后会调用我们定义的回调函数login。在该JavaScript函数中,我们通过得到的对象是否具有一个ExceptionType属性来判断服务端是否抛出异常。如果抛出异常,在通过调用alert方法将错误消息显示出来,否则显示认证成功”。我们再次运行我们的程序并分别输入不合法的用户名和密码,相应的错误消息会以对话框的形式显示出来,具体的显示效果如下图所示。By对于一个新项目,QA通常会首先为新特性创建手工测试用例, 为了之后维护方便,也通常将这些用例存放在一张 Excel 表或者一个专门的测试用例管理系统里。而在项目进行过程中或之后,具备自动化测试能力的QA团队会将手工测试用例转化为代码,加入套件(Suite)中,用于之后的回归。以往我们认为手工测试用例与自动化代码之间存在联系,但并不紧密:.手工测试用例文档很容易阅读,可以帮助学习业务,但因为维护不够灵活,很难跟上快速的变化。依赖手工测试用例对项目进行回归又是及其痛苦的。.自动化测试代码可以很明显的提升效率,但不容易阅读。因为人们通常缺少更新代码注释的动力(没什么外人会用到,老鸟又不依赖它),久而久之我们不知道那一堆自动化用例究竟测了些什么,导致通过率逐步走 低,又无人维护。自动化测试最终土崩瓦解。这似乎是一种宿命般的失败。有些团队希望建立自动化测试体系,却从一开始就遇到类似的问题,导致进展缓慢,无法 持续向老板秀出效果,最终又退缩回原点。原因是什么?怎么去破解这个困局呢?1. 用例文档不应该与自动化代码分离,而应存在于代码中,随着代码的变化而及时更新。2. 用例文档应该简洁,可以自我组织与管理,并以一种清晰的结构被展现和分享。3. 自动化测试用例的运行历史应该被测量和记录,数据可以集中形成几个直接清楚的度量指标,反映一个周期 内的平均质量水平。4. 度量指标应该可以形成简洁好看易懂的质量报告,向相关各方展示测试工作对产品关键方面的评测结果。TestMP的测试用例管理和度量就是按照以上四点,为破局提供了一种解决方案。case的独立性通常一个test suite包含了一组相近的或者有关联的test case.而每一个test case应该只测试一种场景,根据cas e复杂程度的不同场景同样可大可小,可以是某个功能的测试也可以是端到端的完整测试.(当然也有特殊的写法比如工作流测试和数据驱动.)case的独立性又有哪些需要关注的点呢?首先一个test suite内的test case在执行时不应该相互影响,应该将通用的背景部分提取出来放到suite setup 中,允许我随机的跑某一个case或者乱序的跑这些case.如果case的步骤有造成环境被破坏的风险,那应该在case tear down中将环境恢复,并且在case setup中做环境监察以及时的终止 case. suite level和folder level同样要注意独立性 的问题,在 CRT中通常会将数百数千的case放在一起跑,robot并不会规定case执行的顺序所以从某种程度上来说它是 随机的.独立性还体现在case fail时信息的抓取上,经过一个晚上大批case的执行之后,环境通常已被破坏,希望通过保 留现场来用作case失败问题定位是不现实的.所以每个case都应该准确的收集其开始和结束之间的信息.case的可迁移性case的可迁移性主要考虑:case对执行环境的依赖,case对外部设备的依赖,case对测试对象的依赖.a. 避免依赖执行环境,你一直在个人PC上编写的用例并执行测试,但是不久之后你的用例就会被迁移到组内的测试 执行服务器上,之后又被部署到持续集成服务器上,中途也有可能被其他同事下载到他的个人PC上来执行测试.所以在编写用例时我们要避免支持不同平台的不同库(windows,linux)和或者不同的脚本命令(CentOS,RedHat,MacOS)总之要像Java宣扬的那样一处编译处处运行.b. 在通信领域为了测试需要或者扩展测试覆盖,我们会引入一些外部设备如Spirent、Cisco的一些辅助测试设备,各 种网络设备交换机、路由器,还有一些自行开发的模拟设备.外部设备会不断的升级或者更换,在编写用例时我们就需要考虑如何用一套case更好的兼容这些测试设备.我有如下几点建议:i. 首先将外部设备的操作从测试用例步骤中剥离出去,组织成组级别的库.ii.c. 对测试对象的依赖,这里我考虑到的是如果测试对象是一个软件平台,软件平台通常需要适配多种的设备.而设备的 硬件配置可能是多种多样的,CPU、内存、组件的性能和数量都可能不同.对测试对象的依赖不仅要考虑在不同设备上的可执行性,重点要考虑测试覆盖率,由于设备组件的增多你的用例可能 无法覆盖到这些组件,或者捕捉不到某个性能瓶颈,这样测试结果的可靠性也大打折扣.case的可重用性自动化用例的开发通常是一项费时的工作,它需要的时间会是手动执行用例的10倍、20倍甚至更多.我们通过搭建 测试框架和封装资源库来实现最大范围的可重用性.这里我考虑用例的可重用性包括两块:逻辑层的抽象和业务层的重用.对一个产品或者功能进行自动化工作时,我们要考虑这些可用性:首先根据测试逻辑的不同对测试用例进行分类,根据 逻辑的不同选择搭建有针对性的case框架,Work Flow, Data Driven等.建立公共的库,将业务的原子操作抽象出来,并且鼓励其他同事对库进行补充和调用,避免duplicated库开发.抽象的A PI通常需要足够的原子和灵活才会被大众所接受.基于底层API编写的业务操作也具备可重用性,比方说测试场景(背景 资源)的建立、工作流的操作组合、检查点都可以被复用.层次分明的抽取时重用性的基础,提高可重用性可以减少开发时 间,也方便日后的维护中的迭代修改.case的效率不同的case执行时间相距甚远,短则数秒长则数小时甚至数天,数秒钟的简单功能测试用例和稳定性测试耗时数天 的用例本身是没有什么可比性的.但是我当我们放眼某一个或者某一组 case时,我们需要重视效率.不论是敏捷还是持续 集成都讲究快速的反馈,开发人员能在提交代码后快速的获得测试结果反馈,测试人员能在最短的时间内执行更大范围的 测试覆盖,不仅能提高团队的工作效率也可增强团队的信心.在编写用例时我们应该注意哪些方面来提高用例的性能?对于单一的case我的注意点多放在一些细节上,例如:1. 执行条件的检查,如果检查失败,则尽快退出执行.2. 将执行环境搭建或者资源建立和清除抽取到suite甚至folder level,抽取时可能需要做一些组合,但决不允许出现重复的建删操作.3. 用例中不允许出现sleep,sleep通常紧接着hard code的时间,不仅效率低还会因为环境的切换使得执行失败.建议用wait until .来代替.4. 如有不可避免的sleep,我通常会再三确认其是否清楚它的必要性.对于批量的case,我们要如何才能获得更高的效率呢?1.首先我们考虑到可以并行的执行一组case来提高效率,并行方案总有着严苛的条件:测诫背景狮或步騙检沓臣注意厂1#1可N对于呢全没肓交隼的匚耳日巳 通常是件困雅的事,你很薩做 到将所有东西隔离出来,做到互不凰响.不同相同ii用唯一耶利的是将两音的测 试背星詁台在一起.不间N融台背黒;不同的捌试野骤孺 弟睡免相互影响;相同的检查 点可能导致匚耳宫包因为*目同的 原因的感者无法R瞞仙1的r TLTIMr i相同彳目同不同最佳0这种情貝兗全可以考瘫合耳c3S已或音井行上相同相同N网靛砾腋试网|2. 为了获得更
展开阅读全文
相关资源
相关搜索

最新文档


当前位置:首页 > 办公文档 > 解决方案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!