前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MBT探索系列 - PRE/POST 模型在网络接口测试MBT的应用和探索

MBT探索系列 - PRE/POST 模型在网络接口测试MBT的应用和探索

作者头像
腾讯移动品质中心TMQ
发布2018-02-06 16:55:01
1.5K0
发布2018-02-06 16:55:01
举报

目录

⊙MBT 是什么?

⊙PRE/POST 模型是什么?

⊙如何建立PRE/POST模型?

⊙OCL是什么?

⊙OCL怎么建立PRE/POST模型?

⊙PRE/POST模型MBT 实践

一、MBT是什么

MBT中文名称为基于模型的测试, 基于模型的测试属于软件测试领域的一种测试方法。按照此方法,测试用例可以完全或部分的利用模型自动产生。以上所说的模型通常是指对被测系统(SUT,system under test)某些(通常是功能性的)方面的描述。

模型一般都是对被测系统(SUT, system under test)预期行为动作的抽象描述。这些测试用例的集合就是我们平时所称的抽象测试套件(abstracttest suite). 抽象测试套件不可以直接执行于需测试的系统,因为他们不在同一抽象级别。

下图为MBT整体的流程

MBT核心点在于:

  • 如何选择模型
  • 如何生成用用例
  • 如何校验结果

模型直接决定后面两个要素如何进行。

MBT中模型通常有下列几种

  • 前置后条件模型:Pre and post condition models (State based, OCL)
  • 基于转换的模型:Transition based models (FSM, labeled transition systems)
  • 随机模型:Stochastic models (Markov chains)
  • 数据流模型:Data-flow models(Lustre)

其中转换和前置后置条件模型是最常用的模型。对于面向数据的系统(例如网络接口),前置后置条件模型是比较适用的,转换模型例如有限转态机模型(FSM)则比较适合面向交互系统(例如UI系统) .

本文主要讲述PRE/POST模型在网络接口测试MBT中的使用和实践。

二、PRE/POST 模型是什么

网络接口通常是基于一定的契约/约定来执行的.

如我们有一个类Person, 它有一个setAge方法

Class Person {

Public:

int setAge(int newAge);

Private:

Int age;

String name;

}

下面三类条件,它们一起构成一个契约。

1先决条件PRE:

对于(接口)方法来说,先决条件是那些在(接口)方法被调用之前就必须满足的条件,它保证方法可以按照预期来运行。如上面setAge方法,先决条件是输入大于0等等。

2后置条件POST:

对于(接口)方法来说,后置条件是那些(接口)方法被调用之后所要保持的条件(只要先决条件满足)。如上面setAge方法,后置条件是age的大小为输入的值。

3不变量INV:

对象的不变量是那些只要在(接口)方法被调用之前它的先决条件被满足就始终为真的数据。方法调用前和调用后都必须为真. 例如setAge方法,name值应该是不变的.

三、如何建立PRE/POST模型

可以使用OCL 语言来描述 PRE/POST模型。

四、OCL是什么

OCL 全称为Object Constraint Language,中文是对象约束语言。 OCL是UML的一部分。在很多情况下,仅有UML并不能准确地描述系统

OCL可用于指定对象的不变量和方法的输入(前置)和输出(后置条件),使得UML类图更为精确。

例如下图的UML并没有办法描述下列限制:

汽车所有人的年龄限制;

汽车所有人的个数限制;

要求一个人至少要有一辆黑色的车子;

上面的限制可以使用OCL来表述:

如:

汽车所有人年龄必须大于18岁:

contextVehicle

inv: self. owner. age >= 18 (不变量)

一个人所有汽车都应该是黑色的

context Person

inv: self.fleet->forAll(v| v.colour = #black) (不变量)

五、OCL怎么建立PRE/POST模型

OCL不仅仅支持不变量,也支持pre/post

还是上面的UML,我们现在要求 setAge 输入是非负数,并且age属性会被设置为此输入的数值,OCL的表达式为

contextPerson::setAge(newAge:int)

pre: newAge>= 0(pre前置条件)

post: self.age= newAge(post 后置条件)

对于网络接口来说,我们可以使用OCL来描述接口方法的输入(前置条件)和输出(后置条件),还有不变量。

以服务FlightService的子服务updateData 为例, 该服务的功能是更新航班信息,其输入参数包括: 用户名UserName、密码Password和航班信息FlightInfo。

输出参数的数据类型为ReturnCode.

此服务的部分契约为:

  • 输入的航班信息里面的到达时间晚于离开时间, 则返回错误码:(ARR_BEFORE_DEP_TIME = 1)
  • 输入的航班信息里面的到达城市和离开城市不同,则返回正确码 ( NO_ERROR = 0)
  • 输入的航班信息里面的到达时间早于离开时间, 则返回正确码 ( NO_ERROR = 0)等等

⊙我们可以用OCL 来描述上述的约束:

输入的航班信息里面的到达时间晚于离开时间, 则返回错误码:(ARR_BEFORE_DEP_TIME = 1)

context FlightService::updateData(username:UserName,password:Password, flightInfo:FlightInfo)

pre: flightInfo.depTime> flightInfo.arrTime

post: self.result = 1

输入的航班信息里面的到达城市和离开城市不同,则返回正确码 ( NO_ERROR = 0)

context FlightService::updateData(username:UserName,password:Password, flightInfo:FlightInfo)

pre: flightInfo.depCity!= flightInfo.arrCity

post: self.result= 0

输入的航班信息里面的到达时间早于离开时间, 则返回正确码 ( NO_ERROR = 0)

context FlightService::updateData(username:UserName,password:Password, flightInfo:FlightInfo)

pre:flightInfo.depTime < flightInfo.arrTime

post: self. result= 0

六、PRE/POST模型MBT

对于很多网络接口, 大部分情况都是采用自动化的工具来发送请求并且得到响应消息, 但是对于每个用例, 用户需要手动的指定该接口的输入和输出. 还需要制定用例通过相应的校验条件. 新写一个用例的时间都是相同的.

该方法的缺点:

  1. 新加用例时间相同
  2. 用例覆盖度不够
  3. 需要每个用例书写校验条件

如果采用MBT方式的话, 测试人员只需要制定该接口的OCL约束, 指明该接口的输入, 输出和不变量的表达式, MBT生成器可以自动生成测试数据(覆盖率较高), 并且执行测试用例, 在执行完成后, 还能自动根据OCL来校验相应 接口的输入和输出是否满足前置和后置条件从而判断用例是否通过, 效率大大提升.

概括起来的优点为:

1. 用例自动生成,大大减少了书写用例的时间.

2. 用例覆盖率会比较高(采用模糊器生成每个域的随机列表,然后可以采用组合测试 +OCL来生生数据).

3. 用例自动校验结果,减少用例写校验的时间.

4. 将测试时间提前: 可以在开发制定完接口就可以进行接口的MBT测试, 帮助完成测试左移.

使用OCL结合PRE/POST模型来建立MBT体系如下,测试人员输入的仅仅是该接口的OCL描述(即对该接口建立模型),剩下的全是自动化生成和执行的. 

用户可以采用解析OCL来直接生成测试用例,在我们实际的测试中,我们采用了相应的模糊器工具结合OCL来生成相应的测试数据,然后调用执行器得到相应接口的响应消息,最后调用OCL解释来判断该响应是否满足我们执行的约束条件。

以前面的网络服务FlightService的子服务updateData为例, 该服务的功能是更新航班信息,其输入参数包括: 用户名UserName、密码Password和航班信息FlightInfo。

输出参数的数据类型为ReturnCode.

下面约束为: 机票信息中的出发时间要与航班信息的出发时间一致

context

FlightService::updateData(username:UserName,password:Password,flightInfo:FlightInfo)

pre:self.flightInfo.ticketInfo.ticketTime.depTime=self.flightInfo.depTime

post:self.result = 0

对于上面约束, 我们在实际的MBT采用的是下面语法的约束 (我们把响应消息转换为json格式后,它的typeName自动设置为 RspMsg,相应的输入设置为属性reqMsg的值)

context RspMsg

inv: if self.reqMsg.flightInfo.ticketInfo.ticketTime.depTime = self.reqMsg.flightInfo.depTime then self.result = 0 else self.result<> 0

我们将接口的输入和输出作为数据,来校验这个规则。

对于下面数据(满足机票信息中的出发时间要与航班信息的出发时间一致的约束):

OCL对上面的规则校验的结果应该是true

对于下面数据(不满足机票信息中的出发时间要与航班信息的出发时间一致的约束):

对于下面的数据

OCL校验的结果应该是返回false

OCL的工具有很多,如基于EMF的Dresdanocl工具,EMF 本身是比较成熟的建模工具,其中类可以采用Ecore/uml/xds等方式来定义,实例支持xml, xmi等,约束可采用OCL或者java本身来定义, Dresdantocl 是一个提供OCL语法验证的基于EMF的工具。

我们在实践中采用的OCL校验工具是https://github.com/SteKoe/ocl.js,可以根据自己的需求进行扩展和定制,语法相对比较简单也比较轻量。用户可以根据自己的实际情况来选择。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2016-11-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯移动品质中心TMQ 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1先决条件PRE:
  • 2后置条件POST:
  • 3不变量INV:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档