键字驱动的自动化测试
关键字驱动的来源非常自然,从面向对象的思路出发,同样的业务逻辑会自然的编写成一个类或者函数作为关键字来被不同的测试脚本所调用。当测试框架发展到所有的测试过程都已经可以被写好的函数和类所组合完成时,就进化到了关键字驱动的一个高级阶段,这个时候测试用例的开发就变成了测试数据和关键字的组合,并把这种组合工作简化为所有人都很熟悉的表格填写任务,从而最终达到一个由数据和关键字驱动整个测试的效果。
在关键字驱动框架里,你可以创建一些关键字以及相关联的一些方法和函数。然后你创建一个函数库,它里面包含一个读取关键字的逻辑,然后调用相关的动作。
关键字驱动的自动化测试(也称为表驱动测试自动化),是数据驱动自动化测试的变种,可支持由不同序列或多个不同路径组成的测试。它是一种独立于应用程序的自动化框架,在处理自动化测试的同时也要适合手工测试。关键字驱动的自动化测试框架建立在数据驱动手段之上,表中包含指令(关键词),而不只是数据。这些测试被开发成使用关键字的数据表,它们独立于执行测试的自动化工具。关键字驱动的自动化测试是对数据驱动的自动化测试的有效改进和补充。
这种自动化测试的模型主要由核心数据驱动引擎、组件函数、支持库和应用映射表组成。自动化测试首先由初始脚本开始执行,这个脚本把高层测试表传递给高层驱动器,高层驱动器在处理这些表的过程中,遇到中层测试表后就调用中层驱动器,中层驱动器处理中层表时也作类似的处理。当低层驱动器处理低层表时,它尝试着使应用与测试保持同步。当低层驱动器遇到对某一个组件的低层关键字组件时,它判断这个组件的类型并调用相应的组件函数模块来处理这个指令操作。所有这些元素都要依靠映射表中的信息,它是自动化测试模型和被测应用程序的桥梁。支持库主要完成一些文件处理,日志记录和邮件发送等等的功能。
数据驱动的自动化测试框架
“什么是数据驱动呢?很大一部分人肯定认为数据驱动就是把需要参数化的东西写在EXCEL里,然后在跑脚本时调用。如果我告诉你,这其实不是数据驱动,而只是较高级的参数化,你肯定会很惊讶!现在我来解释一下:首先为什么叫数据驱动呢,那么它肯定有驱动的含义,比如你用EXCEL可以控制测试的业务流吗?回答是不能的。那又如何作到驱动呢?所以说我们将测试数据放在独立的文件里只是高级的参数话。而数据驱动,你必须有数据来控制测试的业务流。比如你测一个WEB程序,有很多页面,你可以通过一个数据来控制每次是在哪个页面下工作的(即通过数据来导航到相应的页面)。它是关键字驱动的低级版本,他控制的是函数级的,而关键字是控制动作级的。所以数据驱动应该是可以控制整个测试的”。
在一些复杂的测试用例中,同一个用例包含了很多的测试流程,其中不同的测试流程采用不同的测试输入数据,这个时候测试数据的输入不仅仅是参数的输入,还有业务流程的控制字段的输入(可以理解为逻辑参数),这种情形会更深入的体现数据驱动的含义。
数据驱动的自动化测试是针对上述开发与测试之间紧密耦合问题提出的测试方法。通过建立测试与开发定义的软件元数据的关联——元数据映射表,在测试与开发之间建立松耦合关系。不论测试人员修改测试脚本,还是开发人员修改软件,只需要修改元数据映射表,既可以满足测试与开发同步进行。这样,可以减少测试脚本调试的工作量,更好的实现自动化测试。
接口测试是无界面的功能测试,设计用例思路跟功能测试一样(只是一个注重的是测前端页面,一个注重的是测后端接口)
1.输入参数测试:针对输入的参数进行测试,也可以说是假定接口参数的不正确性进行的测试,确保接口对任意类型的输入都做了相应的处理:输入参数合法,输入参数不合法,输入参数为空,输入参数为null,输入参数超长;
2.功能测试:接口是否满足了所提供的功能,相当于是正常情况测试
3.异常场景,如:请求超时、快速连续点击、请求失败情况(任务型的,失败后是否可以重新下发任务)
附录request 使用:
# -*- coding:utf-8 -*-#__author__ = 'mingo liu''''定义对HTTP请求操作的封装1.http_request是主方法,直接供外部调用2.__http_get,__http_post是实际底层分类调用的方法'''import requests,os,loggingfrom common import opmysqlfrom public import configclass RequestInterface(object): #定义处理不同类型的求参数,包含字典、字符串、空值 def __new_param(self,param): try: if isinstance(param,str) and param.startswith('{'): new_param=eval(param) elif param==None: new_param='' else: new_param=param except Exception as error:#记录日志到log.txt文件 new_param='' logging.basicConfig(filename = config.src_path + '/log/syserror.log',level = logging.DEBUG,format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s') logger = logging.getLogger(__name__) logger.exception(error) return new_param # POST请求,参数在body中 def __http_post(self,interface_url,headerdata,interface_param): ''' :param interface_url: 接口地址 :param headerdata: 请求头文件 :param interface_param: 接口请求参数 :return:字典形式结果 ''' try: if interface_url!='': temp_interface_param = self.__new_param(interface_param) response = requests.post(url=interface_url, headers=headerdata,data=temp_interface_param,verify=False,timeout=10) if response.status_code==200: durtime = (response.elapsed.microeconds) / 1000 # 发起请求和响应到达的时间,单位毫秒 result={'code':'0000','message':'成功','data':response.text} else: result={'code':'2004','message':'接口返回状态错误','data':[]} elif interface_url == '': result={'code':'2002','message':'接口地址参数为空','data':[]} else: result = {'code': '2003', 'message': '接口地址错误', 'data': []} except Exception as error:#记录日志到log.txt文件 result={'code':'9999','message':'系统异常','data':[]} logging.basicConfig(filename = config.src_path + '/log/syserror.log',level = logging.DEBUG,format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s') logger = logging.getLogger(__name__) logger.exception(error) return result # GET请求,参数在接口地址后面 def __http_get(self,interface_url,headerdata,interface_param): ''' :param interface_url: 接口地址 :param headerdata: 请求头文件 :param interface_param: 接口请求参数 :return:字典形式结果 ''' try: if interface_url != '': temp_interface_param = self.__new_param(interface_param) if interface_url.endswith('?'): requrl = interface_url+temp_interface_param else: requrl = interface_url +'?'+ temp_interface_param response = requests.get(url=requrl, headers=headerdata,verify=False,timeout=10) #print response if response.status_code==200: durtime = (response.elapsed.microseconds) / 1000 # 发起请求和响应到达的时间,单位毫秒 result={'code':'0000','message':'成功','data':response.text} else: result={'code':'3004','message':'接口返回状态错误','data':[]} elif interface_url == '': result={'code':'3002','message':'接口地址参数为空','data':[]} else: result={'code':'3003','message':'接口地址错误','data':[]} except Exception as error:#记录日志到log.txt文件 result={'code':'9999','message':'系统异常','data':[]} logging.basicConfig(filename = config.src_path + '/log/syserror.log',level = logging.DEBUG,format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s') logger = logging.getLogger(__name__) logger.exception(error) return result # 统一处理http请求 def http_request(self,interface_url,headerdata,interface_param,request_type): ''' :param interface_url: 接口地址 :param headerdata: 请求头文件 :param interface_param: 接口请求参数 :param request_type:请求类型 :return:字典形式结果 ''' try: if request_type=='get' or request_type=='GET': result=self.__http_get(interface_url,headerdata,interface_param) elif request_type=='post' or request_type=='POST': result=self.__http_post(interface_url,headerdata,interface_param) else: result={'code':'1000','message':'请求类型错误','data':request_type} except Exception as error:#记录日志到log.txt文件 result={'code':'9999','message':'系统异常','data':[]} logging.basicConfig(filename = config.src_path + '/log/syserror.log',level = logging.DEBUG,format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s') logger = logging.getLogger(__name__) logger.exception(error) return resultif __name__ == "__main__": test_interface=RequestInterface()#实例化HTTP请求类 test_db=opmysql.OperationDbInterface()#实例化mysql处理类 sen_sql="select exe_mode,url_interface,header_interface,params_interface from case_interface where name_interface='getIpInfo.php' and id=1" params_interface=test_db.select_one(sen_sql) if params_interface['code']=='0000': url_interface=params_interface['data']['url_interface'] temp=params_interface['data']['header_interface'] headerdata=eval(params_interface['data']['header_interface'])#unicode转换成字典 param_interface=params_interface['data']['params_interface'] type_interface=params_interface['data']['exe_mode'] if url_interface!='' and headerdata!='' and param_interface!='' and type_interface!='': result=test_interface.http_request(interface_url=url_interface,headerdata=headerdata,interface_param=param_interface,request_type=type_interface) if result['code']=='0000': result_resp=result['data'] test_db.op_sql("UPDATE case_interface SET result_interface='%s' WHERE id=1" %result_resp)#将结果更新到case_interface表中 print("处理http请求成功,返回数据是:%s" %result_resp) else: print("处理http请求失败") else: print("测试用例数据中有空值") else: print("获取接口测试用例数据失败")