zoukankan      html  css  js  c++  java
  • 功能点算法及在软件测试中的应用

    ——划分逻辑事务

    在前一篇文章我们讲到,“逻辑事务”是统计功能点指数的最小单元,所以进行科学的划分,对统计的正确性非常重要。另外,划分逻辑事务其实也是一个需求分解的过程,测试工程师可以通过这个过程来分析项目需求,让需求分析工作更加标准化,同时也降低沟通成本,大家围绕逻辑事务进行讨论。

    逻辑事务一般描述的是用户的行为,所以命名一般都是动宾结构,例如“注册淘宝会员”、“查看宝贝的详情”。也有少数的逻辑事务是由一些定时程序产生的,例如“同步用户的最新信息”。有的项目会在需求文档里面专门描述一些“业务规则”,注意,规则不是逻辑事务,规则一定是依附与某个逻辑事务的,例如“不准注册同名的会员”这个规则其实是属于“注册会员”这个逻辑事务。

    在以数据库为基础的WEB应用中,逻辑事务一定是对某项数据进行的增删改查操作,也就是我们常说的CRUDL的其中之一。CRUDL分别代表:

    • Create 创建新数据(注册会员)
    • Read 读取数据的信息(查看宝贝)
    • Update 更新数据(保存收货地址)
    • Delete 删除数据(清空购物车)
    • List 列出一批数据(各种DataGrid)

    下面我们对这5种逻辑事务分别进行分析,并且结合具体的案例来看看划分的规则。如果逻辑事务划分正确,后面的计算出现误差就不会太大。

    Create

    每个WEB应用程序,都是从创建数据开始的,比如“发布新宝贝”、“注册新会员”,创建数据会在数据表中新增记录。创建数据一般由用户在页面上点击按钮触发,也可能是在请求一个URL的时候触发。

    有时候,用户在一个页面点击“新建”,会同时新建两个数据对象,比如注册淘宝会员,会同时创建一个支付宝帐号,这里不能算做2个逻辑事务,而只有1个,这个逻辑事务的“实体”是2个。

    Read

    读取数据的逻辑事务基本都叫“查看XXX的详情”,WEB程序会根据主键,把某个数据对象select出来,把各个字段的值显示在页面上。在分析Read类逻辑事务时,要对页面进行分块分类,因为现在很多WEB页面,都不是单纯显示一个数据,而是用i_f_r_a_m_e的方式,把相关对象都显示出来,这里每个对象都是一个独立的逻辑事务。

    注意,在一些列表页面,比如“我购买过的商品”,是用数据列表的方式,展示出很多商品,这不属于Read类逻辑事务,而是属于List,后面会讲到。Read类一般都是展示单体。

    有些Read类逻辑事务会出现,不同身份的用户查看同一数据对象时,有不同的输出,比如VIP用户查看商品时有价格优惠。这里不能算作2个逻辑事务:“普通用户查看商品”“VIP查看商品”,而应该算1个。“用户的角色”只是一个输入DET。不过,如果普通用户和VIP用户查看商品,完全是两个不同的页面(View不同),那就要算2个逻辑事务了。

    Update

    这类逻辑事务是对已经存在的数据进行更新,一般叫做“保存XXX信息”,不过在某些场景,Update逻辑事务有很多其他的命名,例如“为订单付款”,实际上是更新了订单对象的状态,因此归于Update类。

    在一些信息的保存页面,例如“保存我的收货地址”页面,用户需要先打开某个收货地址的详情页面,然后再进行保存,那么这个详情页面,要算作一个Read类逻辑事务,用户点击按钮保存,算作一个Update类逻辑事务。

    Delete

    删除类逻辑事务出现的不多,一般都是用户点击“删除”按钮,把一个或者几个数据对象删除。老规矩,如果用户一次点击,删除一个对象的同时,又级联删除了这个对象相关的另一个对象的话,只算作一个逻辑事务,实体是2个。删除时一般都会弹出一个对话框,让用户确认,这个确认不算逻辑事务。

    List

    此类逻辑事务最常出现的形态是DataGrid数据表格,例如上文说的“列出我购买过的商品”。这个控件在WEB应用程序中被使用的非常多,它用一种格式在一个页面展示出多个数据对象,并且把这些对象的关键属性(名称、类型)显示出来。除了DataGrid,树型控件也是一个List类的逻辑事务。此外,页面中展示对象的下拉菜单、RadioButton,也要作为单独的逻辑事务来计算,不过前提示,它们显示的是数据对象,如果是“男/女”这样的RadioButton,不是逻辑事务,而购买商品时,选择的“收货地址列表”则是逻辑事务。

    有一些DataGrid控件,支持用户直接在表格里修改数据,这里的修改功能要单独作为Update类逻辑事务计算,与上文有一点不同的是,不需要另算Read类逻辑事务了。

    到这里我们对这5类逻辑事务都分析清楚了,大家划分逻辑事务时,还要明确一个原则,每个逻辑事务的实体个数、输入DET个数、输出DET个数都不能是0,否则就不算逻辑事务。例如,有的页面上设计一个按钮,用户点击后,跳转到另一个页面,这种单纯的跳转,不是逻辑事务。逻辑事务都是对数据对象的操作。大部分情况下,数据对象都在数据库中,也有一些情况,数据对象是文件对象,比如上传图片,图片本身就是实体对象。

    以上所列出的,都是常见的逻辑事务案例,在真实项目中,还可能会遇到一些其他的情况,大家只要根据逻辑事务的判定原则,进行推理,就可以很好的把逻辑事务划分清楚了。

    最后,要说一下测试用例设计。非常相似的,测试用例也是围绕逻辑事务来设计的。在组织用例分类时,基本遵循“项目-功能模块-逻辑事务”这种目录结构。每个逻辑事务的用例,都拥有类似的前置条件、操作步骤、校验方法,所以组织在一起设计,是非常科学的。

    Q:逻辑事务分解对于那种“增删改查”类型的功能点比较适用,但是流程类的功能点,就不合适了吧?
    A:就拿交易流程来说好了,我们在设计交易流程的TC时,是把下单、付款、发货、确认等操作,分别进行设计的,这些操作,其实都是单独的逻辑事务,实际上,开发在设计程序的时候,也是分开做的,不可能全写在一个函数里面。

    Q:我发现有的逻辑事务,比如点击一个按钮以后,程序既做了查,又做了改,按照你Part2里的分类,是不是应该算两个逻辑事务。
    A:这个怪我没说清楚,这应该是算一个逻辑事务,他可以同时包含多个CRUD的action。

    Q:我们以前设计TC很多都是基于一个页面的,现在按照这种方式,一个页面会分解成多个逻辑事务,这样感觉会比较零散。
    A:测试设计和测试执行是有区别的,测试设计的目标是把被测系统分析清楚,并不是编写出完整的执行脚本,实际上在测试执行过程中,有经验的测试工程师是会把几个逻辑事务放在一起测,效率极高。

    我们仍然会分别对CRUDL这五类逻辑事务进行分析,因为他们的输入和输出的特点,各有不同。不过,对于“实体”的计算,各类逻辑事务的计算方法相同,所以先单独讲一下实体。

    淘宝系统里存在下面这些实体:会员、宝贝、交易记录、宝贝类目、评价记录、店铺等等。实体的英文原名是Entity Type,也就是我们平时讨论中经常出现的“对象”,经常接触代码的工程师会在代码里发现很多“xxxDO”,比如UserDO、OrderDO,这些和实体是完全对应的。另外还有一个简单的办法来识别实体,就是看数据库的表,一般一个实体肯定至少对应一张表,比如会员这个实体在数据库里,必然有一张users表。

    分析一个逻辑事务有哪些实体,是分析的第一步,也是最重要的一步。实体越多,开发和测试的复杂度越高。从MkII算法里也能看出,实体的系数是1.66,远高于输入和输出。另外,分析实体可以帮助测试工程师搞清楚,这个事务的范围,对事务有一个全局的概念。分析完后,测试工程师一般会这么说:“哦,这个事务跟这几个对象有关!”在新人学习和测试设计评审中,实体的分析也能起到非常大的帮助作用。

    下面开始分类讲CRUDL的输入和输出:

    Create

    注册会员、发布新宝贝,这都属于Create类型逻辑事务,这类事务一般都有一个内容较多的“表单”,里面有一些输入框、checkbox、radiobutton和一个确认提交按钮,这里的每个控件,都要计算为1个输入DET。需要注意,radio控件一般会有多个选项,不能算多个输入,而只能算一个;提交按钮也要算1个输入。除了这些页面控件类输入,还有一类输入,是“隐含”的。比如卖家在发布新宝贝时,卖家自己的userid就是一个输入,因为在发布成功后,这个宝贝会拥有卖家的userid,只是这个id并不需要卖家填写,而是放在系统缓存里。虽然是隐含输入,却也参与了逻辑运算,因此要计数。这是Create的两类输入。

    Create事务的输出一般会有以下一些信息,“注册成功”、“此会员名已被人注册”、“密码太短”。当用户试图执行这个事务,系统给用户所有可能的提示信息,都要记为一个输出。有些输出跟某个输入,有直接的逻辑关系,比如“此会员名已被人注册”只跟“会员名”输入框里所填的信息有关,有的输出,则是由好几个输入组合在一起,才能出现,分析的时候,需要弄明白,不过这点区别不影响计数。

    如果把逻辑事务看成一个“函数”,那么输入就可以抽象为函数的输入参数,而输出就是函数的所有可能性的返回值,以及函数抛出的各种异常。后面几类逻辑事务,也可以抽象为这种定义,大家后面自己推理试一试。

    Read

    Read类事务是读取一个对象的详细信息,比如我们查看一个宝贝的详细信息。它的输入个数一般比较少,其中最基本的,就是这个对象的主键id,比如宝贝的id。如果不同类型的用户查看宝贝时,会有不同的显示信息,那么用户的userid和用户类型这2个要记为输入。如果宝贝的某些属性会影响显示,比如鞋城宝贝会有个图标,那么输入也要+1。其实如果业务逻辑复杂,输入也不少。我们可以把这些输入抽象的称为“影响对象显示的一些属性”。

    一般来说Read的输出都比较多,这个对象能显示在页面上的属性,都要记为输出,比如“宝贝名称”、“价格”、“颜色”等等。除了文字类,图片也是输出,比如宝贝的缩略图和表示宝贝属性的一些小图标,都算。另外,有的图片和Label有链接,这里的链接要单独算输出,因为一个纯文本,肯定没有一个附带http链接的文本信息量多。

    Update

    Update事务的输入和输出数量可多可少,关键看系统Update的规模,比如“编辑宝贝”跟“发布新宝贝”相比,输入输出的数量都非常多。像“修改我的登录密码”这样的,数量就非常少了。Update事务的输入输出识别,与Create类非常相似,因为大部分Update事务也是表单提交的方式。

    这里需要注意的是,系统中会存在一些“不起眼”的Update事务,分析时千万别漏了。比如大部分会员有多个收货地址,然后在列表中有一个鼠标悬停出现的“设置为默认收获地址”的按钮,当用户点击的时候,只是修改收获地址的一个属性,非常的隐蔽。这也是一个逻辑事务,它的输入是用户id,收货地址id,输出只有1个,就是点击按钮后,系统提示修改成功,非常简单,但是不要遗漏。

    Delete

    Delete类事务的分析相对简单一些,多数删除功能,都是直接对数据进行删除,因此输入一般就是数据主键id这1个。不过,有一些数据在删除前,需要先做一些逻辑判断,看看能不能删,这样输入就多了,相应的实体也会增加。比如,“已经发布的宝贝不能删除”,那么“宝贝发布状态”就是1个输入,“已经有交易的宝贝不能删除”,那么实体就不仅仅是宝贝,还有交易记录,输入也要增加“交易记录id”;如果规则更复杂“有未完成交易的宝贝不能被删除”,那么输入还要增加“交易状态”,依此类推。

    List

    List事务是一个重点,最后讲,它的输入输出计算比较复杂,而且多变,所以大家不仅要理解我下面讲的东西,还要能自己推理,分析自己实际遇到的各种List。List事务实质上跟Read很像,不同在于Read只看1个对象,List要看多个。首先看最常出现的List事务:DataGrid,这种控件一般是一个二维表格,它的输入与Read类似,比如我的订单列表的输入是会员userid,我的已买到订单列表还要增加订单类型这个输入,我的近3个月已买到订单再加订单时间,等等。有些列表上方,会有查询功能,比如按照名称查询,这些查询项会影响列表的显示数据,因此是输入。大家如果想象一下这个列表对应的sql语句,就好理解了,where后面跟的都是输入。

    DataGrid的输出比较直观,每一列就是一个输出,对应sql语句里的select后面的字段,注意,有些列显示的不仅仅是文字,还有图片,颜色,这些都要单独计数。

    对于DataGrid来说最纠结的要属“翻页”和“排序”功能,这究竟是算输入还是输出呢?经过推理我们发现,翻页功能对显示的数据是有影响的,比如我翻到第二页(假设每页10个数据对象),很多程序会控制从数据库里读取的数据,只取出第11到20的数据,也是在sql的where后面加条件,所以,翻页属于输入的计数,流行的翻页一般是“上一页”“下一页”这样的按钮或者是直接输入数字翻页,只要出现1种,输入+2,要是两种都有,+4。再说说排序,排序对应的sql标记是order by,不是select也不是where,比较另类,究竟算哪边合适呢?在MkII的相关资料里也没有找到答案。通过比较发现order的操作与where更接近一些,相似度更大,都是影响数据的检索范围,因此我们把排序也认定为输入。DataGrid如果有1列提供排序功能,那么输入+1,多列的话,依此类推。

    前文曾经提到过,显示数据对象的radio控件,也是List类的事务,它的输入,就是显示这些数据的条件。比如买家购买商品时,有个收货地址的radio控件,因为是“我的”地址,所以userid是1个输入。输出就要看这个radio展示了数据对象的哪些属性,有几个算几个。比如收货地址的姓名、省、市、区、邮编,这些都是不同的字段,但是在radio里全部拼在一起,要算5个输出。

    还有一类控件使用也较多,就是树形控件,这也是List类的逻辑事务。输入算法就不说了,同上,重点说输出。树形控件里的每个节点,一般都是一个数据对象,节点会有名称、颜色、加粗、小图标这么几种显示元素,用来表示数据对象的属性,这些都是输出,单独计数。树形控件有特殊的展开、折叠功能,这个不太好分类,我们直接规定,输出+4,因为在折叠上我们需要投入一点测试成本。如果一棵树里展示了两种数据对象,别忘了实体要+1。

    List的例子我们就讲3个,大家还有可能遇到各种五花八门的List逻辑事务,只要掌握这个原则:输入会影响显示数据的范围,而输出是展示数据的各个属性。大家只要掌握规律,细心推理,遇到问题方可迎刃而解。

    功能点分析法应用在软件测试中,它最核心的价值究竟是什么呢?

    让我们先看看软件开发,这是跟测试离得最近的工作类型。开发工程师工作大致可以分为“设计”和“编码”两步。设计一般是使用UML语言,借助类似于Rose这样的工具,绘制一些UC图、类图、ER图等等。这些设计图决定了最终的编码该如何实施。另外,当其他的开发工程师需要了解这个project时(例如评审),ta会先看设计文档,从设计文档中掌握开发思路,然后再阅读代码,了解细节。

    由于UML语言中,包含了大量的约定和规则,因此开发工程师只需要花费较少的工作量,就能表达出充足的信息。而阅读UML设计文档的其他人,也能很快从UML设计中了解设计人员的思路。试想一下,如果让读者直接看代码,需要花费多少倍的时间,才能达到相同的目的。这就是设计模型的价值,不仅帮助设计人员自己整理思路,也帮助其他读者快速交流信息。

    对于软件测试来说,也有“设计”和“编码(实施)”两个阶段的工作。设计是我们设计测试用例的过程,也就是我们考虑如何做;实施就是我们执行测试的过程,有时是手工执行,有时是写脚本让计算机执行。因此,测试用例是我们的“设计文档”,是我们交流测试方法,评审测试方案的核心。但是只依靠测试用例,我们感觉存在很多问题:

    • 测试用例数量多,难以阅读
    • 测试用例结构五花八门,风格迥异,不同团队间不好交流
    • 测试用例很难清楚表达需求逻辑,每次用例评审,要花费大量时间,讲解需求逻辑
    • 测试用例描写的是测试细节,较难看出测试的思路和重点

    在这种情况下,我们需要一种测试设计模型,用来解决上面那些问题。事实上,测试设计模型不是唯一的,我们允许团队中使用各种设计模型来设计测试用例。以前我们曾经用UML来设计,这是一种设计模型。不过UML开发工程师用起来合适,我们测试用就不是特别合适,毕竟它的优势,是描述程序的开发实现。另外,设计模型和测试用例模式,应该是成对出现的,也就是说,用什么样的设计模型,就应该有合适的用例模式与之对应。一成不变的用例模式,其实是不存在的,它必须要紧跟设计模型。

    这就是我们选择功能点分析算法的最主要目的:寻找一种新的设计模型,改善我们的测试用例设计过程,精简测试文档(因为模型可以包含很多信息),让测试团队用一种相同的设计模型进行工作,减少沟通成本,更好的支撑我们的业务测试。

    现在我们面对的,是互联网软件产品,这一类软件的特点,不同于传统的应用软件,互联网应用软件多使用BS结构,MVC的开发模型,有庞大的数据库作为支撑,需求和用户界面多变,市场竞争激烈,等等。在这种条件下,测试工程师往往没有太多时间设计用例,而是要快速的面对大量新需求和需求变更,第一时间找出程序的bug,这才是王道。

    下面,我们讲一下,怎么样使用功能点分析的方法,来设计测试用例。

    如part2所说,我们拿到一个project,首先需要把它拆分成逻辑事务,然后针对每个逻辑事务,讨论使用何种测试方法。有些事务属于核心事务,必须要重点测试,要设计完整的用例,有些事务只需编写一个简单的check list,就足够指导测试执行了,有些事务甚至根本不用写任何文档,测试工程师拿到手也知道该怎么测试。在这里我不想再回答“一个完全不懂的测试新人,看不到用例,该怎么测试?”这样的问题。测试新人正式上岗之前,必须接受测试技术培训,和project的业务培训。如果是跨团队合作(其实这种场景很少),那么PTM也要出面先做一些测试方案的讲解,绝对不能把测试用例直接扔给其他工程师。

    这里我们推荐使用freemind或者xmind这样的思维导图软件,来做功能点分析。root node一般是project的名称,比如购物车。然后下级node是各个模块的名称,然后就是逻辑事务的名称。本文选了一个逻辑事务作为案例:买家在宝贝详情页面点击购买。通过对这个事务的功能点分析,再推导出相应的测试用例。事实上,淘宝测试团队的twork小组,正在开发通过freemind图,自动生成测试用例的功能,所以在下面的讲解中,我会不断比较,freemind图和最终生成的用例。

    首先在逻辑事务的node下创建:输入、输出、实体3个node,先列出所有的实体。实体对用例设计并没有什么影响,只是告诉读者,这个事务跟哪些对象有关,这样可以清楚的界定用例范围。如下图:

    “01点击立即购买”是我们今天要讲的事务,02~06也是事务,但是今天不会讲到。使用twork把这个设计图导入以后,将会产生对应的目录结构,注意,一直到逻辑事务这一层,都和设计图相同,再往下,会根据设计的不同有所变化,而并不产生“输入”“输出”这样的测试集。如下图:

    下面重点要讲输入,这和测试用例的设计有很大关系。这个事务的输入比较多,不过我们如果分类来看,就会比较清楚。首先看最上面那3个实体的主键id,这3个输入是必须要参与程序的逻辑运算的,但是与测试用例无关。如下图:

    有一类输入,比如买家状态,会有很多枚举值,这些枚举值会产生非常优先的判定,比如说,一个被处罚的买家,是不能购买宝贝的。这一个条件就可以直接产生一个确定的结果,这些结果,一般是用页面文字的方式告知用户,所以要算作“输出”。注意:输出的项,不一定都在“输出”这个node下面,而是有很大一部分,会挂在输入项的下面,表示和输入的逻辑关系,这种关系也是设计图中的重要信息,如下图:

    在导入twork以后,会在逻辑事务的测试集下,产生一个叫做“买家状态”的测试集,这些枚举值将变成输入条件,而后面的输出结果,将变成期望结果。如下图:

     

    还有一种输入项,比如页面表单的输入框,会产生一堆输出:“不能为空”“不能超过20字符”等等,在设计图中,我们可以把这一堆输出,直接挂在输入项下面,这样,也会产生一组用例,也就是我们常说的页面校验。

    上面所说的,是输出和输入紧密关联的情况,产生的用例比较简单。除此以外还会出现更复杂的情况,当多个输入组合在一起的时候,才会产生一定的输出。这时,就需要把这些有逻辑关系的输入组织起来,在设计图里单独建一个node,注意这个node上不要标记Input,因为它不是一个输入项,而只是一个分组。真正的输入项在下面。如下图:

    根据这一部分的设计,会生成一组比较复杂的用例,每个输入项,会成为一列,这里有4个,就是4列,另外再加1列“期望结果”。这是twork中一种新的用例编写模式,叫做测试数据驱动模式(TD驱动),看起来眼熟,其实就是“判定表”,我们以前用Excel写用例的时候,就是这么写的,现在在twork中,更进了一步,用户可以随意定义每个测试集的列,而每一行,也作为一个用例对象,保存在数据库里。如下图:

    需要说明的是,这种复杂的组合,程序是无法自动生成用例的,因为要完全排列组合的话,用例太多,不靠谱,而且具体的组合情况,跟需求有很强的关系,程序更是难以了解。程序能做的是,生成用例表格结构,同时创建一些空白的用例,然后我们自己在里面填一下值就可以了,写用例速度快,而且用例非常直观。

    大家注意到了,在设计图中,输入、输出、实体我们都用不同的标记给标识出来,这样导入twork时,程序便会自动算出每个逻辑事务的功能点指数分值,非常方便,所以文章开头说,这个指数计算,只是一个副产品。

    通过上面的分析过程我们可以看出,功能点分析图与测试用例之间,存在非常紧密的逻辑关系,之前几篇文章我们也讲到,功能点分析是一种非常好的分解分析需求的手段。通过这张分析图,读者可以迅速了解设计者的思路,以及了解每个逻辑事务大致的逻辑。这时如果需要看细节,可以进入twork,很快找到这个逻辑事务的测试集,并查看下面的用例。

    上面的例子,列举的是Create类的逻辑事务,以及里面两种最常见的输入组合。Update类和Delete类事务,跟这个差不多,这里不再细讲。它们的共同点在于,输入一般较多,并且存在一些逻辑组合,而输出,相对比较简单。

    至于Read类和List类事务,在设计图会有一些区别,这两种逻辑事务输入相对较少,而输出项很多,它们主要的测试重点在于,校验页面展示,比如“查看宝贝信息”,输出项可能会有30个以上,这时,使用check list的方式会比较方便,并不用编写复杂的用例,只需说明,需要校验哪些点即可。如果Read类事务也有复杂的输入,比如查看宝贝信息会有:宝贝类型、宝贝类目、宝贝消保类型这些输入,那么就参考刚才Create类的方式即可。

    总之,设计用例重点关注业务逻辑,对于展示类的事务,尽量用简单的方式完成测试设计,至于有些一看到页面,就知道应该怎么测试的事务,即使不写用例,我觉得也问题不大。只要在设计图中把这个事务的输入输出实体都标识清楚,我相信测试工程师就可以很好的完成测试工作。即使交给另一位工程师,只要他也了解这种设计模式,那么也可以测得很好。

    功能点算法以及在软件测试中的应用的系列文章,到这里总共编写了4章,我们需要告一段落了。这4章主要讲了功能点算法的概念,以及基本的应用,后面我们会实践一段时间,等积累了足够的经验,我们再继续这个话题,一起期待Part5回归吧。

  • 相关阅读:
    台州 OJ 3847 Mowing the Lawn 线性DP 单调队列
    洛谷 OJ P1417 烹调方案 01背包
    快速幂取模
    台州 OJ 2649 More is better 并查集
    UVa 1640
    UVa 11971
    UVa 10900
    UVa 11346
    UVa 10288
    UVa 1639
  • 原文地址:https://www.cnblogs.com/yanghj010/p/5110398.html
Copyright © 2011-2022 走看看